Poslední DirectDraw aneb sněhu není nikdy dost

3. díl - Poslední DirectDraw aneb sněhu není nikdy dost

Tomáš Herceg       20.04.2007       VB.NET, DirectX, Grafika       14502 zobrazení

V tomto díle si naprogramujeme jednoduchý spořič obrazovky, který simuluje sníh. Použijeme z větší části to, co již z minulého dílu umíme, naučíme se vykreslovat obrázky se zvětšováním. Toto je již poslední díl, ve kterém se budeme věnovat 2D grafice, od dalšího dílu začneme s vykreslováním pomocí Managed DirectX.

V tomto díle článku si ukážeme třetí způsob, jak vytvořit aplikaci pod rozhraním DirectX. V prvním dílu jsme si ukázali postup pomocí časovače, což bylo příliš neobratné. V minulém dílu jsme používali herní smyčku, která má ovšem také své neduhy. Nejlepší cesta je využívat překreslovací událost formuláře Paint. V ní zavoláme proceduru Render a pak zavoláme Me.Invalidate, což je metoda, která oznámí systému, že formulář se trošku změnil a že bude třeba jej v budoucnu překreslit. Nepotřebujeme Application.DoEvents, protože Invalidate nevykresluje hned, ale až když na to má systém čas.

Vytvořte si tedy nový projekt s názvem Snow typu Windows Appliaction. Formulář přejmenujte v Solution Exploreru na formSnow. Přidejte naše známé knihovny do referencí, otevřete okno kódu formuláře, vymažte jeho obsah, a nakopírujte tam základní procedury z minulého dílu.

 Imports Microsoft.DirectX 
 Imports Microsoft.DirectX.DirectDraw 
  
 Public Class formSnow 
  
     Dim dev As Device       'zařízení 
     Dim backBuffer As Surface, backBufferDesc As SurfaceDescription     'BackBuffer a jeho parametry 
     Dim frontBuffer As Surface, frontBufferDesc As SurfaceDescription   'FrontBuffer a jeho parametry 
     Dim clip As Clipper     'oříznutí 
  
     Private Sub formSnow_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove 
         'pokud je pohyb větší, ukončit aplikaci 
         Static mm As Integer = 0 
         mm += 1 
         If mm > 5 Then Me.Close() 
     End Sub 
  
     Private Sub formSnow_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click 
         'ukončení programu 
         Me.Close() 
     End Sub 
  
     Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown 
         'ukončení programu 
         Me.Close() 
     End Sub 
  
     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
         'vypnout překreslování pozadí 
         Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True) 
         Me.SetStyle(ControlStyles.Opaque, True) 
         'vytvořit a nastavit zařízení 
         createDevice() 
         'vytvořit buffery 
         createBuffers() 
         'nahrát obsah 
         loadContents() 
     End Sub 
  
     Public Sub createDevice() 
         'vytvořit a nastavit zařízení 
         dev = New Device() 
         dev.SetCooperativeLevel(Me, CooperativeLevelFlags.FullscreenExclusive) 
     End Sub 
  
     Public Sub createBuffers() 
         'kontrola 
         If Not Me.Focused Then Exit Sub 
  
         'nastavit zařízení 
         dev.SetCooperativeLevel(Me, CooperativeLevelFlags.FullscreenExclusive) 
  
         'vytvořit FrontBuffer 
         If frontBuffer IsNot Nothing Then 
             frontBuffer.Restore() 
         Else 
             frontBufferDesc = New SurfaceDescription() 
             frontBufferDesc.SurfaceCaps.PrimarySurface = True 
             frontBufferDesc.SurfaceCaps.Flip = True 
             frontBufferDesc.SurfaceCaps.Complex = True 
             frontBufferDesc.BackBufferCount = 1 
             frontBuffer = New Surface(frontBufferDesc, dev) 
         End If 
  
         'vytvořit BackBuffer 
         If backBuffer IsNot Nothing Then 
             backBuffer.Restore() 
         Else 
             backBufferDesc = New SurfaceDescription() 
             backBufferDesc.SurfaceCaps.BackBuffer = True 
             backBuffer = frontBuffer.GetAttachedSurface(backBufferDesc.SurfaceCaps) 
         End If 
  
         'nastavit oříznutí 
         clip = New Clipper(dev) 
         clip.Window = Me 
         frontBuffer.Clipper = clip 
     End Sub 
  
     Public Sub loadContents() 
  
     End Sub 
  
     Public Sub animateSnow() 
  
     End Sub 
  
     Public Sub Render() 
         'kontrola 
         If Not Me.Created Then Exit Sub 
         If frontBuffer Is Nothing Or backBuffer Is Nothing Then Exit Sub 
         If Not Me.Focused Then Exit Sub 
  
         Try 
  
             'vykreslit scénu na BackBuffer 
             backBuffer.ColorFill(Color.Black) 
  
             'animovat sníh a vykreslit vločku 
             animateSnow() 
  
             'převrátit buffery 
             frontBuffer.Flip(backBuffer, FlipFlags.Wait) 
  
         Catch ex As Exception 
  
             'po obnovení z minimalizace 
             If ex.GetType() Is GetType(SurfaceLostException) Then 
                 createBuffers() 
             End If 
  
         End Try 
     End Sub 
  
     Private Sub formSnow_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint 
         'renderovat obrazovku 
         Render() 
         Me.Invalidate() 
     End Sub 

V tomto bloku kódu je již vše, co je třeba k vykreslení prázdného okna. Na začátek jsem přidal procedury Form_KeyDown, Form_MouseMove a Form_Click, které při jejich zavolání ukončí náš spořič. Procedura MouseMove má čítač, který počítá, kolikrát se zavolala, a pokud se zavolala alespoň 5x, ukončí program. To proto, že tato procedura má ve zvyku spouštět se, i když se myš ani nehne, zejména při startu programu ve starších verzích Windows.

Úplně na konci je procedura Paint, která renderuje a připravuje obrazovku pro překreslení. Ta zastupuje smyčku, kterou jsme použili v minulém díle.

Načtení obrázku snéhové vločky

Snéhovou vločku si stáhněte tak, že pravým tlačítkem klikněte na tento obrázek  a vyberete volbu Uložit obrázek. V Solution Exploreru klikněte dvakrát na položku My Project, rozbalí se okno vlastností projektu.

Přejděte na záložku Resources a rozbalte nabídku tlačítka Add Resource, kde vyberete položku Add Existing File.... Vyberte stažený soubor a potvrďte volbu. Tím jsme obrázek zaintegrovali do projektu a nemusíme jej dodávat spolu s aplikací, je již přibalen v EXE souboru. To právě potřebujeme, spořič obrazovky by měl být pouze jediný soubor, který se nahraje do složky System32 v adresáři s nainstalovaným operačním systémem. Přípona se musí změnit na SCR, aby se soubor objevil v nabídce spořičů obrazovky.

Na první záložce v okně vlastností projektu zaškrtněte uprostřed volbu Make single instance application, která zajistí, že tato aplikace nepůjde spustit dvakrát za sebou. To má totiž Windows občas také ve zvyku, spouštět spořiče hned několikrát. Asi aby se víc uspořilo :-).

Nyní k načtení obrázku sněhové vločky, je to opakování, známe to již z minulého dílu. Do procedury LoadContents vložte tento kód:

         'nahrát sněhovou vločku 
         Dim desc As New SurfaceDescription() 
         flake = New Surface(My.Resources.vlocka, desc, dev) 
  
         'nastavit vločce průhlednost 
         Dim ck As New ColorKey() 
         flake.SetColorKey(ColorKeyFlags.SourceDraw, ck)

Nezapomeňte do deklarací nahoře vložit tento řádek, kde deklarujeme proměnnou flake:

 Dim flake As Surface 

Princip generování a pohybu sněhových vloček

Algoritmus, který jsem vymyslel a zvolil, je trochu komplikovaný, K zachování věrnějšího efektu budeme generovat vločky různých velikostí, které budou padat různou rychlostí (která do určité míry bude záviset na jejich velikosti), a tyto vločky se budou ještě pohybovat vodorovně, aby byl jejich pohyb zajímavější.

Každá vločka si při vytvoření automaticky zvolí pozici X, na které začíná. Pozice Y se nastaví kousek nad horní okraj obrazovky.

Dále se nastaví velikost vločky. Minimální je 8x8 pixelů, maximální je 36x36 pixelů. Protože chceme, aby větších vloček bylo více, použijeme kvadratickou závistost namísto lineární. Vygenerujeme náhodné číslo od 0 do 24x24 a to odmocníme, dostaneme číslo od 0 do 24. Přičteme k němu 8 a máme velikost vločky. Větších vloček bude více, protože vyšší čísla budou pravděpodobnější. Například na číslo menší nebo rovno 12 se odmocní jen čísla od 0 do 144, ale na číslo větší nebo rovno 12 se odmocní hodnoty od 144 do 576, což je výrazně větší interval a tudíž i výrazně větší pravděpodobnost. Tím pádem bude menších vloček méně než těch větších.

Rychlost spočítáme podle převrácené hodnoty druhé mocniny velikosti vločky, od které odečtěme 7. K tomu přidáme ještě náhodné číslo vhodně vynásobené, aby poměr byl vyvážený. Pokud by rychlost vyšla moc velká, rušilo by to, takže ji funkcí Math.Min případně zmenšíme na nějaký limit. Tento poměrně komplikovaný vztah zajistí, že menší vločky se budou pohybovat rychleji než vločky větší. Ke zvětšení účinku používáme opět druhou mocninu velikosti.

Každá vločka bude také harmonicky kmitat podél vodorovné osy, abychom docílili zajímavějšího efektu. Harmonický pohyb se počítá funkcí sinus. Tato funkce, jak jistě všichni víme, vrací hodnoty od -1 do 1. Protože pohyb o 1 pixel není téměř vidět, musíme hodnotu vhodně vynásobit, a to tzv. amplitudou, což je maximální výchylka. Tu určíme pro každou vločku náhodně. Dále potřebujeme vygenerovat úhlovou rychlost, tj. jak rychle se mení úhel, pomocí nějž počítáme sinus. Tento úhel neustále roste, a hodnoty funkce kmitají tam a zpět. No a samozřejmě si každá vločka musí pamatovat svůj aktuální úhel, abychom k němu mohli přičíst v dalším snímku úhlovou rychlost a přepočítat vodorovnou pozici.

A na závěr má každá vločka svůj lifetime, tedy čas v milisekundách, za jaký se rozpustí. V praxi to vypadá tak, že některé vločky zmizí ještě před tím, než zajedou za okraj obrazovky.

Celé to vypadá složitě, pokud algoritmus nechápete, nevadí, jednodušší (bez kmitání a se stejnou velikostí vloček, ale náhodnou rychlostí) byste jistě zvládnuli.

Do deklarací (mimo procedury) přidejte tento kód. Obsahuje datovou strukturu pro data vločky, pole pro tisíc sněhových vloček, generátor náhodných čísel a proměnné pro počítání délky posledního snímku.

     Structure Vlocka        'informace o sněhové vločce 
         Dim tX, X, Y As Single 
         Dim Speed As Single 
         Dim Lambda As Single 
         Dim LambdaSpeed As Single 
         Dim LambdaFactor As Single 
         Dim LifeTime As Single 
         Dim Size As Integer 
     End Structure 
     Dim v(999) As Vlocka    'pole sněhových vloček 
  
     Dim LastTime As Integer = Environment.TickCount()       'poslední vykreslení snímku 
     Dim DeltaTime As Integer        'počet milisekund, kolik trvalo vykreslení posledního snímku 
     Dim Generated As Single = 0     'kolik vloček již bylo v tomto snímku vygenerováno 
  
     Dim r As New Random()   'generátor náhodných čísel 

V kódu máme již připravenou proceduru animateSnow, která se spustí jedno za každý snímek. O kousek posune sněhové vločky, pokud to jde, tak vygeneruje nové, a nakonec vločky vykreslí. Proměnná Generated určuje, kolik vloček se za snímek již vygenerovalo, aby se vločky generovaly postupně. Zde je tedy tato procedura:

         'spočítat, kolik trval poslední snímek 
         DeltaTime = Environment.TickCount - LastTime 
         LastTime = Environment.TickCount 
  
         'projít všechny vločky, pohybovat s nimi a vykreslit je 
         Generated -= 2 
         For i As Integer = 0 To v.Length - 1 
             With v(i) 
                 If (.LifeTime <= 0 Or .Y > 768) And Generated < 10 Then 
                     'generovat vločku 
                     .X = r.Next(dev.DisplayMode.Width)                  'náhodná X souřadnice 
                     .Y = -36                                            'nad horním okrajem obrazovky 
                     .Lambda = 0                                         'harmonické horizontální knitání 
                     .LambdaFactor = r.NextDouble() * 10 + 2             'amplituda kmitání 
                     .LambdaSpeed = r.NextDouble() * 0.001 + 0.001       'úhlová rychlost kmitání 
                     .LifeTime = (r.Next(9000) + 9000)                   'doba života vločky 
                     .Size = CInt(Math.Sqrt(r.Next(24 * 24) + 8 * 8))    'velikost vločky (víc větších vloček) 
                     'náhodně spočítat rychlost tak, aby závisela na velikosti vločky 
                     .Speed = Math.Min(1 / (.Size * .Size - 14 * .Size + 49) + 0.1 + r.NextDouble() * 0.05, 0.2) 
                     Generated += 1 
                 End If 
  
                 If .LifeTime > 0 And .Y < dev.DisplayMode.Height Then 
                     'posunout vločku 
                     .LifeTime -= DeltaTime 
                     .Y += .Speed * DeltaTime 
                     .Lambda += .LambdaSpeed * DeltaTime 
                     .tX = .X + .LambdaFactor * Math.Sin(.Lambda) 
  
                     'vykreslit vločku 
                     BltStretch(flake, .tX, .Y, .Size, .Size) 
                 End If 
             End With 
         Next

Téměř posledním momentem je procedura BltStretch, která vykresluje obrázky se zvětšením. Stará se o to, abychom nekreslili mimo buffer, což by vyvolávalo chyby, naše vločky tedy ořízne a vykreslí jen jejich viditelné části.

     Public Sub BltStretch(ByRef s As Surface, ByVal x As Integer, ByVal y As Integer, ByVal imageWidth As Integer, ByVal imageHeight As Integer) 
         'vykreslení obrázku se zvětšením 
         Dim left As Integer = 0, w As Integer = s.SurfaceDescription.Width, width As Integer = imageWidth 
         Dim top As Integer = 0, h As Integer = s.SurfaceDescription.Height, height As Integer = imageHeight 
  
         'spočítat ořezový čtverec 
         If y < 0 Then top = -y : height = imageHeight + y 
         If y + imageHeight > dev.DisplayMode.Height Then height = dev.DisplayMode.Height - y 
         If x < 0 Then left = -x : width = imageWidth + x 
         If x + imageWidth > dev.DisplayMode.Width Then width = dev.DisplayMode.Width - x 
  
         'pokud je na obrazovce, vykreslit ho 
         If x + imageWidth > 0 And y + imageHeight > 0 And _ 
            x < dev.DisplayMode.Width - 1 And y < dev.DisplayMode.Height - 1 Then 
             backBuffer.Draw(New Rectangle(x + left, y + top, width, height), s, _ 
                 New Rectangle(left / imageWidth * w, top / imageHeight * h, width / imageWidth * w, height / imageHeight * h), DrawFastFlags.SourceColorKey) 
         End If 
     End Sub

Teď by nám mělo vykreslování padajícího sněhu fungovat.

To nejlepší nakonec

Nyní se musíme podívat, jak fungují spořiče obrazovky. Jak jsem již psal nahoře, jedná se o normální EXE soubor, který má ovšem příponu změněnou na SCR. Musí být ve složce System32 (případně System na Windows 95, 98 a ME), kterou najdete v adresáři s nainstalovaným operačním systémem Windows.

Pokud tento soubor spustíme jen tak, nebo s parametrem /c, musí se zobrazit formulář s nastavením. My však zatím nastavení podporovat nebudeme, takže bude vhodné pouze zobrazit hlášku, že tento spořič nemá žádné nastavení. Pokud spořič spustíme s parametrem /s, spustí se samotný spořič. Pokud jej spustíme s parametrem /p, náš spořič se ukončí, protože nebudeme podporovat jeho náhled v malém okénku v dialogu výběru spořiče obrazovky. Pokud bude parametr jiný, tak spořič také nespustíme.

Pro spouštění a manipulaci s událostmi na úrovni aplikace má Visual Basic speciální třídu MyApplication. Dostaneme se k ní přes okno vlastností projektu, kde hned na první záložce klikneme na okno Application Events. Otevře se příslušné okno kódu, do kterého vložíme tuto proceduru:

         Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup 
  
             If e.CommandLine.Count = 0 Then 
                 'pokud nejsou žádné argumenty příkazového řádku, odmítnout spustit aplikaci 
                 e.Cancel = True 
  
             Else 
                 Select Case e.CommandLine(0).ToLower.Trim 
                     Case "/p"       'náhled nepodporujeme 
                         e.Cancel = True 
  
                     Case "/s"       'spustit spořič obrazovky 
                         Me.MainForm = formSnow 
  
                     Case Else       'odmítnout zobrazit nastavení 
                         MsgBox("Pro tento spořič není možné žádné nastavení.", MsgBoxStyle.Information, "Snow") 
                         e.Cancel = True 
  
                 End Select 
             End If 
  
         End Sub 

A tím je náš spořič obrazovky hotov. Stačí jen v menu Build vybrat příkaz Build Project a vygeneruje se nám spustitelný soubor. Ten najdete nejspíše v Dokumentech, kde je složka Visual Studio 2005\Projects. V ní by měly být všechny vaše projekty, pokud je tedy neukládáte jinam. Najděte si složku svého projektu a v podsložce Bin\Release byste měli najít svůj soubor EXE. Ten zkopírujte do systémové složky Windows, změňte příponu na SCR, a to je celé.

Pravým tlačítkem klikněte na plochu, vyberte Vlastnosti a na kartě Spořič obrazovky si vyberte Snow. Můžete dát náhled, a pak se už jen kochat krásným padajícím sněhem.

V příštím díle se již vrhneme na 3D grafiku.

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

3. Poslední DirectDraw aneb sněhu není nikdy dost 20.04.2007
2. Smyčka a animace 19.04.2007
1. První aplikace v DirectX 19.04.2007

 

Mohlo by vás také zajímat

Řešené příklady v ASP.NET - díl 1.: Aplikace pro zamlouvání sedadel (část 1)

V této části vytvoříme databázi, napíšeme základní infrastrukturu a nakonfigurujeme přihlašování uživatelů pomocí knihovny Altairis Web Security.

Řešené příklady v ASP.NET - díl 4.: Jak na dlouhotrvající úlohy

Občas potřebujeme ve webových aplikacích provádět dlouhotrvající úlohy, které se nevejdou do jednoho HTTP požadavku. V tomto článku si ukážeme jeden z možných přístupů k řešení tohoto problému.

Práce s časovými pásmy a letním časem v aplikaci a databázi - díl 1.: Úvod do časových pásem a letního času

Ve článku se snažím popsat úskalí, která přináší konverze času přes více časových pásem a pravidel pro počítání letního času.

 

 

Nový příspěvek

 

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

mohl byste blíže vysvětlit parametry, myslím tím objekty zde, tečkovou konvenci, zda jsou parametry vždy generovány nebo jestli do nich uživatel může zasahovat? není mi to úplně jasné.

Proč je např. jednou sender typu object, jindy system.object, jaký význam má parametr e, zda se identifikátor handles musí vždy vztahovat jen k proceduře u které je uveden(souvislost dle jména), apod.

Díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

Rád bych věděl kdy bude pokračování. na 3D už se těším.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

rád bych věděl zda mám očekávat další článek. Předem děkuji.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ne, Managed DirectX se již dále nevyvíjí. Nástupcem je XNA.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

Co bych prosím musel napsat místo

 backBuffer.ColorFill(Color.Black)

aby aplikace neběžela Fulscreen, ale vločky padaly přímo na ploše?

Nebo to asi nebude jen tak jednoduché.

Nepotřebuji, aby plocha byla funkční, jen aby vločky padaly přes plochu. (doufam, že to je srozumitelné)

Nebo mi stačí jednoduchý příklad, jak na ploše rozpohybovat obdelník pomocí myši.

XX = Windows.Forms.Cursor.Position.X
backBuffer.FillStyle = 1
backBuffer.FillColor = Color.Green
backBuffer.DrawBox(XX, 1100, XX + 300, 1090)

Moc díky za radu.

Bouda

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

Dobrý den. V prní řadě Vám musím pochválit tento článek, opravdu mi hodně pomohl, při práci s DirectX. A dále by mě zajímalo kdy bude pokračování s 3D?

nahlásit spamnahlásit spam 11 / 11 odpovědětodpovědět

Diskuse: Poslední DirectDraw aneb sněhu není nikdy dost

Především bych chtěl poděkovat za velice podnětný a přitom jasně a srozumitelně napsaný článek. Pouze bych se chtěl zeptat, jak je to s využitím výše zmiňované knihovny, o které Microsofti všude píší, že již nadále není doporučována a v příštích edicích DirectX již nebude ani podporována. Je toto varování s ohledem na vývoj nových aplikací přehnané, nebo je možno (ve VB) podobný příklad řešit jinou knihovnou - předpokládám Dorect3D. V rámci DirectX SDK jsou ukázky podobných aplikací s využitím právě knihovny Direct3D, ovšem vše pouze pro C# (managed kód, unmanaged samozřejmě pro C++). Je toto známkou toho, že uvedené knihovny není možné ve VB použít ve stejném rozsahu, jako je tomu u C#, nebo pouze autoři nepředpokládají, že by se někdo takto graficky náročnými aplikacemi ve VB zabýval?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Předně děkuji za pochvalu. VB.NET má stejné možnosti jako C# co se týče managed kódu. Je tedy omezen pouze na Managed DirectX. To, co píšete o DirectDraw, je sice pravda, ale to je pouze varování pro případ, že byste chtěl aplikaci převádět na vyšší verzi DirectX. A DirectX 10 nabízí takové množství klíčových změn, že ještě dlouho potrvá, než budeme moci vyvíjet DX10 aplikace, důležitá je totiž podpora na straně hardwaru a OS, DX10 totiž půjde pouze na Windows Vista. Rozhodně si myslím, že zde tato technologie ještě dost dlouho zůstane.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Děkuji za objasnění. Předesílám, ža nejsem programátor - na to jsem již hodně stár, ale spíš praktik, který si sem tam potřebuje udělat nějaké to speciální "udělátko". Snad právě proto mne Váš web jako celek nadchl a když jsem na něj narazil, téměř celý jsem jej přelouskal. Obdivuji vaši grácii, s jakou zvládáte přiblížit i ta mírně složitější témata i nám, kteří již nemají čas ani možnosti se programování "věnovat na plný úvazek" a chtěl bych Vás pochválit i za Vaši trpělivost - tam, kde v jiných diskusích již na adresu některých tazatelů (a to i těch slušně se dotazujících) létají odkazy na Lamy a jim podobné (a to ještě v těch slušnějších případech) Vy vysvětlíte nebo alespoň tazatele navedete na správnou cestu poznání i v případě zcela triviálních dotazů. Držím Vám palce, doufám, že Vám Váš web někteří exhibicionisté svými příspěvky nezkazí a těším se na další pokračování Vašich článků.

Viktor Langer

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkujeme.

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback