Warsztat.GD

Programowanie => Językoznawstwo => C# => Wątek zaczęty przez: Radomiej w Marzec 30, 2013, 19:44:00

Tytuł: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Marzec 30, 2013, 19:44:00
Witam, jestem w trakcie robienia biblioteki do konsoli. Napotkałem jednak dosyć poważny problem, konsola z C# jest bardzo wolna. Jeśli chcę narysować naraz kilkanaście linii tekstu to widać  jak znaki są rysowane. Dodając do tego jeszcze obsługę kolorów dla poszczególnych znaków zwalnia do prędkości żółwia. Jest sposób by ją jakość przyśpieszyć? np. bezpośrednie odwołanie do biblioteki od konsoli? czy nic się z tym za bardzo nie da zrobić?
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Kebab_u_Turka w Marzec 30, 2013, 20:29:23
W jaki sposób "wyrzucasz" coś do konsoli ?

Niemożliwe, żeby "wyrzucanie" dużej ilości danych do konsoli było wolne, coś musisz robić źle.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xirdus w Marzec 30, 2013, 20:55:02
Problemem jest to, że funkcje obsługujące standardowe wyjście są wolne, dlatego trzeba jak najmniej razy je wywoływać i jak najwięcej wypisywać za jednym zamachem. Najprościej jest zaimplementować podwójne buforowanie: robisz tablicę 2D o wielkości okna konsoli i całe rysowanie robisz najpierw na tamtej tablicy, a potem jedną funkcją wypisujesz to wszystko na prawdziwą konsolę. Nie jestem jednak pewien, czy C# ma ku temu odpowiednie narzędzia - przynajmniej ja nie zauważyłem ich nigdzie tutaj (http://msdn.microsoft.com/en-us/library/system.console.aspx). Natomiast jest to możliwe, i nawet proste, przy użyciu C/C++ i WinAPI - robisz tablicę 2D struktur typu CHAR_INFO (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682013(v=vs.85).aspx) i wypisujesz ją funkcją WriteConsoleOutput() (http://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx). Jak chcesz, to przejrzyj sobie źródła mojej ruletki (http://warsztat.gd/projects/ruletka_nienawidze_winapi), gdzie tego właśnie użyłem, i efekt jest super (i nie wynika to tylko z faktu użycia C++ - jak robiłem Snake'a na początku swojej nauki, to też miałem problem z wolnym coutem - działo się dokładnie to, co opisałeś).
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Marzec 30, 2013, 22:45:36
No tak myślałem że im mniej wywołań tym lepiej. Ale z drugiej strony potrzebuję żeby istniała możliwość zmiany koloru tła i czcionki dla każdego znaku. Mój kod rysujący jest taki:
     
  public void DrawConsole()
        {
            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    Console.BackgroundColor = bufforColorBackgroundMap[x, y];
                    Console.ForegroundColor = bufforColorForegroundMap[x, y];
                    if (x < sizeX - 1)
                    {
                        Console.Write(bufforCharMap[x, y]);
                    }
                    else
                    {
                        if (y != sizeY - 1)
                        {
                            Console.WriteLine(bufforCharMap[x, y]);
                        }
                        else
                        {
                            Console.Write(bufforCharMap[x, y]);
                        }
                    }
                }
            }
        }
Ale nie wiem jakby to zrobić żeby zachować daną funkcjonalność ale zarazem przyśpieszyć. Chyba faktycznie przerzucę się na C++ jeśli tutaj nie da rady jakoś tego problemu rozwiązać.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Fiołek w Marzec 30, 2013, 23:00:11
Z System.Console wiele więcej nie wyciągniesz.

Żeby użyć WriteConsoleOutput nie musisz wcale używać C++ - możesz wykorzystać P/Invoke. CHAR_INFO ma prostą strukturę, więc można łatwo to przenieść do C#(czy to z pomocą Marshall (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.aspx) czy z wykorzystaniem fixed pointerów i normalnych struktur). Wywołanie WriteConsoleOutput też jest dość proste. Zabawy będzie więcej niż przy C++, ale jeśli reszta kodu korzysta z dobrodziejstw C# to nie widzę sensu przechodzenia ;)
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: ShadowDancer w Marzec 31, 2013, 03:14:12
Och, na pewno w c# będzie szybciej i mniej bawienia się - z tego prostego powodu, że ktoś już to zrobił:
http://stackoverflow.com/questions/2754518/how-can-i-write-fast-colored-output-to-console
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Marzec 31, 2013, 12:24:35
Och, na pewno w c# będzie szybciej i mniej bawienia się - z tego prostego powodu, że ktoś już to zrobił:
http://stackoverflow.com/questions/2754518/how-can-i-write-fast-colored-output-to-console


To jest to czego bym potrzebował, ale przydałoby mi się jakieś objaśnienie jak działa parametr attribute?
Z tego co widzę da radę w nim zmienić tło i kolor czcionki ale jak zmodyfikować go modyfikować żeby mieć pełną paletę RGB tła i koloru czcionki?
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: ShadowDancer w Marzec 31, 2013, 14:17:38
AFAIK bez powershella nie możesz mieć pełnej palety barw w windowsowej konsoli.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Marzec 31, 2013, 14:19:38
@Radomiej: Masz 2 opcje:

1. Użyć jakiegoś przeportowanego UNIX-owego terminala, który ma takie ficzery (a dodatkowo frytki do tego). Przy czym nie każdy z nich obsługuje 256 kolorów, a pełne RGB raczej nieliczne. Przy okazji będzie szybszy.
2. Napisać terminal na własne potrzeby. Przy okazji będzie szybszy. Możesz napisać dedykowany dla Twojej gry, lub uniwersalny - jakieś zaczepienie o tym drugim: http://xion.org.pl/2011/01/26/bo-konsola-to-tez-okno/.

Kolorów w Windowsowym terminalu jest 16, chociaż paletę można zdefiniować sammu (ale tylko od Visty wzwyż). http://gynvael.coldwind.pl/n/konsola_w_windowsie_kolory_pl_znaki.

@up: Ach, kiedy wy, Windowsowcy, nauczycie się rozróżniać, co jest zadaniem shella, a co terminala?...
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Marzec 31, 2013, 16:14:43
Dobra poszukam może coś jest na C#, chociaż w sumie i te 16 kolorów być może starczy. Dzięki za pomoc.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xion w Marzec 31, 2013, 19:06:43
AFAIK bez powershella nie możesz mieć pełnej palety barw w windowsowej konsoli.
Psh to tylko shell, tj. zwykły program. To, jakie kolory można wyświetlać w "konsoli" to kwestia emulatora terminala, który używamy. Domyślnie i Psh i cmd.exe używa tego standardowego (zwanego dla niepoznaki właśnie 'konsolą') który oczywiście nie jest kompatybilny z ANSI terminalami.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: ShadowDancer w Marzec 31, 2013, 21:48:42
Hmm, faktycznie, widocznie oprócz powershella instalowałem jakiś niestandardowy terminal.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Kwiecień 02, 2013, 14:24:54
Mam jeszcze mały problem, ponieważ przy wyświetlaniu napisów z polskimi znakami w ich miejscu wyświetlają mi się inne znaki. Polskie znaki jednak są ale pod innymi wartościami. Stąd pytanie: jakie jest kodowanie c++ konsoli i czy mogę je łatwo zmienić z poziomu C#? czy może powinienem użyć klasy encoding z bibliotek C# żeby to przekonwenterować?
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Kwiecień 02, 2013, 15:24:22
No i jak to jest, że trzeba w jednym temacie 2 razy linkować ten sam artykuł? :P
http://gynvael.coldwind.pl/n/konsola_w_windowsie_kolory_pl_znaki

Powinieneś użyć UTF-8, czyli pod Windows strony kodowej 65001 - to jedyne słuszne, standardowe kodowanie (jeśli chcesz wiedzieć, dlaczego - http://kos.gd/2013/02/say-hello-to-unicode/). Więc SetConsoleOutputCP(65001); i jazda.

Przy czym kodowanie plików ze źródłem musi się zgadzać - czyli też UTF-8. Jeśloi z jakichś dziwnych powodów byłby to problem, to zostaje używać escape sequences w literałach.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Rolek w Kwiecień 02, 2013, 15:43:01
Powinieneś użyć UTF-8, czyli pod Windows strony kodowej 65001 - to jedyne słuszne, standardowe kodowanie (jeśli chcesz wiedzieć, dlaczego - http://kos.gd/2013/02/say-hello-to-unicode/). Więc SetConsoleOutputCP(65001); i jazda.
Jeśli nie interesuje Cię możliwość przekierowania wyjścia do pliku (a przy kolorowaniu konsoli zapewne nie), to możesz obsługiwać konsolę przy użyciu unicodowych(UTF-16) funckji dedykowanych do konsoli.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Kwiecień 02, 2013, 16:53:11
@up - AFAIK to nie UTF-16, tylko UCS-2, czyli nie obejmuje całego Unicode. Wybrali takiego potworka, bo UTF-8 wtedy nie istniało, albo było bardzo młode i wydawało im się, że sprawiałoby problemy - jak historia pokazała, jednak nie sprawiało. Więc lepiej zostawić te Windosowe widechary w spokoju i korzystać z normalnych, jednobajtowych charów z tekstem i stroną kodową UTF-8.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Kos w Kwiecień 02, 2013, 18:13:41
@up Aithne mi kiedyś wytknęła, że od Windows ileśtam (2000? Xp?) coś tam się zmieniło i jest już UTF-16. Ale nie pamiętam o co dokładnie chodziło (i.e. gdzie surrogate pairs nie były rozumiane, a teraz są).
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Aithne w Kwiecień 02, 2013, 20:31:39
Wybrali takiego potworka, bo UTF-8 wtedy nie istniało, albo było bardzo młode i wydawało im się, że sprawiałoby problemy
Wybrali takiego potworka, bo wtedy (1992-1993!) goście od unikodu myśleli, że 16 bitów na code point wystarczy im na zawsze. Jak się potem okazało, że lepszą liczbą jest 21 bitów, to był rok 1999. Microsoft nie mógł od tak złamać kompatybilności, a dodawać trzeciego zestawu funkcji (dla UTF-8 lub UTF-32) chyba nie chcieli ;)

od Windows ileśtam (2000? Xp?) coś tam się zmieniło i jest już UTF-16. Ale nie pamiętam o co dokładnie chodziło (i.e. gdzie surrogate pairs nie były rozumiane, a teraz są).
Wszędzie poza systemem plików, dla którego nazwy to sekwencje bajtów, można UTF-8 dać, a NTFS się nie zorientuje, tylko potem przy próbie odczytu API systemu mogą stwierdzić "NEIN!" ;)
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Kwiecień 02, 2013, 20:53:41
@up - Jak dokładnie jest z tym NTFSem? Bo chyba coś kojarzę, że Gynvael pisał, że NTFS w kernelu chodzi właśnie na widecharach, a Ty mówisz, że bajtach - to już się zgubiłem...
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Kwiecień 02, 2013, 23:25:28

[DllImport("kernel32.dll", SetLastError = true)]

        private static extern int SetConsoleOutputCP(int wCodePageID);

//****
   [STAThread]
        public void DrawConsole()
        {
            SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
            if (!h.IsInvalid)
            {
                int i = 0;
                CharInfo[] buf = new CharInfo[sizeX * sizeY];
                SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = (short)sizeX, Bottom = (short)sizeY };
               
                for (int y = 0; y < sizeY; y++)
                {
                    for (int x = 0; x < sizeX; x++)
                    {
                        buf[i].Attributes = (short)(bufforColorForegroundMap[x, y] + (int)bufforColorBackgroundMap[x, y] * 16);
                        buf[i].Char.UnicodeChar = bufforCharMap[x, y];                       
                        i++;
                    }
                }
                SetConsoleOutputCP(65001);               
                bool b = WriteConsoleOutput(h, buf,
                new Coord() { X = (short)sizeX, Y = (short)sizeY },
                new Coord() { X = 0, Y = 0 },
                ref rect);

            }
        }

Mam coś takiego, teoretycznie powinno hulać jak trzeba ale wszystko pozostaje bez zmian. Nawet wpisując różne wartości w SetConsoleOutputCP nic się nie zmienia. Próby konwersji z UTF8 na inny format też nic nie dają.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Kwiecień 03, 2013, 00:27:35
Może cziocnka? Genialnie zrobione :D - http://support.microsoft.com/default.aspx?scid=kb;en-us;Q99795.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Aithne w Kwiecień 03, 2013, 14:30:24
Jak dokładnie jest z tym NTFSem? Bo chyba coś kojarzę, że Gynvael pisał, że NTFS w kernelu chodzi właśnie na widecharach, a Ty mówisz, że bajtach - to już się zgubiłem...
Na jednym i drugim jednocześnie. Dla systemu plików to są bajty, ale muszą występować parami, bo inaczej poczułyby się samotne ;)
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Radomiej w Kwiecień 03, 2013, 18:09:33
Może cziocnka? Genialnie zrobione :D - http://support.microsoft.com/default.aspx?scid=kb;en-us;Q99795.
To możliwe ale nie chce mi się bawić w zmienianie czcionki. Zwłaszcza że ta opcja dostępna jest dopiero od Visty. Dobra to zrobię najwyżej własny konwenter i powinno być ok.
Tytuł: Odp: Wolna konsola - jak przyśpieszyć?
Wiadomość wysłana przez: Xender w Kwiecień 04, 2013, 01:44:14
@up - "For Windows NT, Windows 2000, and Windows XP the currently available Unicode console font is the Lucida Console TrueType font. "