SDL 1.2 naar 2.0 migratiehandleiding
This is a translation of the original English version. Dit is een vertaling van de originele Engelstalige versie. |
Contents
- SDL 1.2 naar 2.0 migratiehandleiding
Vertalingen
Une traduction de cette page par Developpez.com est disponible ici.
Als u deze pagina wil vertalen naar andere talen, laat Ryan dit dan weten: icculus@icculus.org
Introductie
Na vele jaren in ontwikkeling te zijn geweest, is SDL 2.0 eindelijk uitgebracht!
We zijn nogal trots erop, en we willen graag dat spellen die SDL 1.2 gebruiken onmiddellijk de overstap maken. Aangezien dit kan aanvoelen als een afschrikwekkende taak, bevat dit document simpele, stapsgewijze instructies over hoe te migreren naar de nieuwe library. We denken dat u zult ziendat het niet zo moeilijk is als u denkt, en u zult veelal ofwel functie-aanroepen vervangen met directe equivalenten of enige hacks in uw brontekst om te gaan met 1.2 tekortkomingen ongedaan maken.
We denken u zeer tevreden zult zijn met SDL 2.0, zowel met de nieuwe mogelijkheden als de betere ervaring dan met SDL 1.2. Dit document probeert niet te omvatten al de geweldige nieuwe dingen in SDL2--dat zijn er vele--maar enkel de dingen die u moet doen om het direct draaiende te krijgen. Als u uw brontekst eenmaal omgezet hebt, raadpleeg dan zeker de nieuwe dingen; u zult waarschijnlijk ook een deel ervan willen toevoegen aan uw applicatie.
Overzicht van nieuwe mogelijkheden
Dit zijn de meest belangrijke nieuwe mogelijkheden van SDL 2.0:
- Volledige 3D apparatuuracceleratie
- Ondersteuning voor OpenGL 3.0+ voor diverse profielen (kern, compatibiliteit, foutopsporing, robuustheid, enz)
- Ondersteuning voor OpenGL ES
- Ondersteuning voor meerdere vensters
- Ondersteuning voor meerdere schermen
- Ondersteuning voor meerdere geluidsapparaten
- Android en iOS ondersteuning
- Simpele 2D render API die, achter de schermen, Direct3D, OpenGL, OpenGL ES, of software-rendering kan gebruiken
- Haptische terugkoppeling beschikbaar onder Windows, Mac OS X en Linux
- XInput en XAudio2 ondersteuning voor Windows
- Atomaire operaties
- Energiebeheer (vaststellen resterende batterijduur, enz)
- Aangepaste venstervormen
- 32-bit geluid (int en float)
- Vereenvoudigde spelbesturingsapparaat API (de joystick API is nog immer beschikbaar!)
- Ondersteuning voor aanraakschermen (multi-touch, veegbewegingen, enz)
- Betere fullscreen ondersteuning
- Betere toetsenbord ondersteuning (scancodes vs toetscodes, enz).
- Berichtvensters
- Klembord ondersteuning
- Simpele slepen-en-neerzetten ondersteuning
- Fatsoenlijke unicode invoer en IME ondersteuning
- zlib licentie in plaats van LGPL.
- Veel van de oude ergernissen van 1.2 zijn verdwenen
- Vele andere dingen!
De Introductie pagina heeft een meer omvangrijke lijst van welke mogelijkheden SDL in zijn algemeenheid biedt (inclusief oude 1.2 mogelijkheden).
Op zoek naar meer informatie
De beste plekken met informatie zijn:
deze wiki
de testen meegeleverd met SDL, in de test/ directory (blader online)
de SDL mailinglijst
Overstappen van SDL 1.2 naar 2.0
Enkele algemene waarheden
Er is geen compatibiliteitslaag ingebouwd in SDL2. Als een API veranderde voor 2.0, hebben we de oude functies veranderd of verwijderd waar dit logisch is. Als u uw 1.2 programma laat wijzen naar de 2.0 headerbestanden, zal het waarschijnlijk niet willen compileren. Dit document zal proberen u te leiden langs de meest belangrijke wijzigingen, en degenen die het meest waarschijnlijk zijn u te laten struikelen.
Er is geen SDL_main! Nou, oké, er is, en het doet nu wat het altijd bedoeld was te doen: een klein stukje brontekst zijn dat het verschil verbergt tussen main() en WinMain() onder Windows. Er is geen initialisatie-brontekst erin, en het is volkomen optioneel. Dit betekent dat u SDL kunt gebruiken zonder dat u het overneemt in uw 'hoofdlijn', wat mooi is voor invoegtoepassingen die SDL gebruiken, of scripttalen met een SDL module. Al de dingen waarvoor u de 1.2 SDL_main zou willen zijn nu in SDL_Init() waar ze thuishoren.
Er is geen SDL parachute meer. Wat 1.2 SDL_INIT_NOPARACHUTE noemde is nu de standaard en enige toestand. Dit zou problemen veroorzaken als iets anders dan de hoofd-thread crashte, en het zou belemmeren dat toepassingen hun eigen signaal/uitzondering handlers instellen. Aan de negatieve kant, sommige platformen ruimen fullscreen video goed goed op na crashes. U moet uw eigen crash handler installeren, of SDL_Quit() aanroepen in een atexit() functie of iets dergelijks als u zich hierover bezorgd maakt. Merk op dat op Unix platformen, SDL nog immer SIGINT afvangt en koppelt aan een SDL_QUIT event.
Video
Het instellen van een spel met de nieuwe video API
De video API is het meest drastisch gewijzigd van 1.2. Behoeften zijn heel erg veranderd sinds SDL's API was ontworpen eind jaren 1990. Om met moderne apparatuur en OS mogelijkheden om te gaan, hebben we de oude 1.2 video API bijna compleet vervangen.
Maak u geen zorgen, de nieuwe is tamelijk geweldig, en als u eenmaal begrijpt wat is veranderd, zult u zeer tevreden zijn met de nieuwe mogelijkheden die het kan brengen voor uw 1.2 spel. We zullen die later bespreken.
Het goede nieuws: als uw spel OpenGL gebruikte, hoeft u waarschijnlijk niet veel te doen: verander een handvol functie-aanroepen naar hun SDL2 equivalenten, en u bent klaar.
Voor 2D graphics bood SDL 1.2 een concept genaamd "oppervlakken," dat waren geheugenbuffers van pixels. Het scherm zelf was een "oppervlak," als u aan 2D software rendering deed, en we verschaften functies om pixels te kopiëren ("blitten") tussen oppervlakken, onderwijl formaten omzettende waar nodig. U was bijna altijd aan het werk op de CPU en in systeem RAM, niet op de GPU en in het videogeheugen. SDL 2.0 verandert dit; u krijgt nu bijna altijd apparatuuracceleratie, en de API is dienovereenkomstig aangepast.
Als u een 2D spel hebt, is de kans groot dat u een van drie benaderingen hebt genomen om te renderen. Ze zullen die allemaal langsgaan, maar eerst, laten we praten over inleidende dingen.
Herinnert u zich SDL_SetVideoMode()? Dat is volledig verdwenen. SDL 2.0 staat u toe meerdere vensters te hebben, dus de oude functie was niet logisch meer.
U had wellicht iets als dit:
SDL_WM_SetCaption("Mijn spelvenster", "spel");
SDL_Surface *scherm = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN | SDL_OPENGL);
Wat nu dit is:
SDL_Window *scherm = SDL_CreateWindow("Mijn spelvenster",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
U kunt zien dat dit gelijkenis toont aan 1.2. Het verschil is dat u meerdere vensters kunt hebben (als u wilt), en u hebt meer controle over ze. SDL_WM_SetCaption is weg, want we willen toestaan dat elk venster zijn eigen titel heeft (u kunt het later veranderen met SDL_SetWindowTitle()), en we willen u een vensterpositie laten opgeven (of, in dit geval, SDL_WINDOWPOS_UNDEFINED laten gebruiken aangezien het ons niet uitmaakt waar het systeem het plaatst. SDL_WINDOWPOS_CENTERED is ook een goede keuze).
U krijgt extra krediet als u gebruikers een beeldscherm laat opgeven voor het venster: SDL2 laat u ook systemen met meerdere monitoren beheren. Maakt u zich op dit moment echter geen zorgen daarover.
Nu uw venster terug is op het scherm, is het tijd om over uw strategie te spreken. SDL2 heeft nog steeds SDL_Surface, maar wat u wilt, waar mogelijk, is het nieuwe SDL_Texture. Oppervlakken zijn nu altijd in systeem RAM, en worden altijd bewerkt door de CPU, dus daaraan willen we ontsnappen. SDL2 heeft een nieuwe rendering API. Het is bedoeld voor gebruik door simpele 2D spellen, maar met name, het is bedoeld om al het software-renderen in video RAM te krijgen en naar de GPU. En zelfs als u het enkel wilt gebruiken om het werk van uw software-renderer naar het scherm te krijgen, brengt het enige zeer mooie voordelen: waar mogelijk, zal het OpenGL of Direct3D gebruiken achter de schermen, wat betekent dat u gratis snellere blits, een werkende Steam Overlay, en schaalbaarheid krijgt.
Het is als volgt ingericht.
SDL_SetVideoMode() wordt SDL_CreateWindow(), zoals we eerder besproken. Maar hoe regelen we de resolutie? Als uw spel hard-gecodeerd was op 640x480, bijvoorbeeld, liep u waarschijnlijk aan tegen monitoren die dat niet op fullscreen-resolutie aankonden op dat moment, en in venstermodus zag uw spel er waarschijnlijk uit als een geanimeerde postzegel op zeer high-end monitoren. Er is een betere oplossing in SDL2.
We roepen SDL_ListModes() niet meer aan. Er is een equivalent in SDL2 (roep SDL_GetDisplayMode() aan in een lus, SDL_GetNumDisplayModes() keer), maar in plaats daarvan gaan we een nieuwe mogelijkheid gebruiken genaamd "fullscreen desktop," die SDL zegt "geef me het hele scherm en wijzig de resolutie niet." Voor ons hypothetische 640x480 spel, kan dit er zo uitzien:
SDL_Window *sdlVenster = SDL_CreateWindow(titel,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
0, 0,
SDL_WINDOW_FULLSCREEN_DESKTOP);
Merk op dat we niet specificeerden 640 of 480...fullscreen desktop geeft u het hele scherm en negeert elke afmeting die u opgeeft. Het spelvenster zou direct moeten verschijnen, zonder te hoeven wachten op het verspringen van het scherm in een nieuwe resolutie, en we zullen de GPU gebruiken om te verschalen naar de bureaubladgrootte, wat de neiging heeft sneller en netter ogend te zijn dan als een LCD een lagere resolutie nabootst. Bijkomend voordeel: geen van uw achtergrondvensters verschalen zichzelf op dit moment.
Nu hebben we een renderingskader nodig.
SDL_Renderer *renderer = SDL_CreateRenderer(sdlVenster, -1, 0);
Een renderer verbergt de details van hoe we tekenen in het venster. Dit zou achter de schermen Direct3D kunnen gebruiken, OpenGL, OpenGL ES, of software-oppervlakken, afhankelijk van wat het systeem biedt; uw brontekst blijft onveranderd, ongeacht wat SDL kiest (hoewel u welkom bent om één of andere soort renderer af te dwingen). Als u wilt proberen om sync-naar-vblank af te dwingen om scheuren te verminderen, kunt u gebruiken SDL_RENDERER_PRESENTVSYNC in plaats van nul voor de derde parameter. U moet hier geen venster creëren met de SDL_WINDOW_OPENGL vlag. Als SDL_CreateRenderer() beslist dat het OpenGL wil gebruiken, zal dat het venster naar behoren voor u bijwerken.
Nu dat u begrijpt hoe dit werkt, kunt u dit ook allemaal doen in één stap met SDL_CreateWindowAndRenderer(), als u niet iets bijzonders wilt:
SDL_Window *sdlVenster;
SDL_Renderer *sdlRenderer;
SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &sdlVenster, &sdlRenderer);
Ervan uitgaande dat deze functies niet mislukten (controleer altijd op NULLs!), bent u klaar om te starten met tekenen op het scherm. Laten we om te beginnen het scherm opschonen naar zwart.
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_RenderPresent(sdlRenderer);
Dit werkt zoals u zou denken; teken in zwart (r,g,b allen nul, volledig alfa), schoon het hele venster op, plaats het opgeschoonde venster op het scherm. Jazeker, als u SDL_UpdateRect() gebruikte of SDL_Flip() om uw bits op het scherm te krijgen, gebruikt de render API SDL_RenderPresent().
Er is hier één extra algemeen ding om in te stellen. Aangezien we SDL_WINDOW_FULLSCREEN_DESKTOP gebruiken, weten we niet daadwerkelijk de hoeveelheid scherm waarnaar we moeten tekenen. Gelukkig hoeven we dat niet te weten. Een van de mooie dingen van 1.2 is dat u kon zeggen "Ik wil een 640x480 venster en het maakt me niet uit hoe je dat gedaan krijgt," zelfs als het gedaan krijgen betekende het venster centreren in een hogere resolutie ten behoeve van uw applicatie.
Voor 2.0, de render API laat u dit doen...
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "lineair"); // maak de verschaalde rendering gladder ogend.
SDL_RenderSetLogicalSize(sdlRenderer, 640, 480);
...en het zal het juiste ding doen voor u. Dit is fijn aangezien u de logische rendergrootte kunt wijzigen om verschillende effecten te bereiken, maar het primaire gebruik is dit: in plaats van te proberen het systeem te laten werken met uw rendergrootte, kunnen we nu uw rendergrootte laten werken met het systeem. Op mijn 1920x1200 beeldscherm denkt deze applicatie nu te praten tegen een 640x480 resolutie, maar SDL gebruikt de GPU om op te schalen om al die pixels te gebruiken. Merk op dat 640x480 en 1920x1200 niet dezelfde beeldverhoudingen zijn: SDL draagt ook daar zorg voor, verschaalt zo veel mogelijk en letterboxt het verschil.
Nu zijn we echt klaar om te beginnen met tekenen.
Als uw spel alleen maar volledig gerenderde frames naar het scherm wil krijgen
Een speciaal geval zijn oldschool, met software gerenderde spellen: de applicatie wil zelf elke pixel tekenen en de uiteindelijke verzameling pixels efficiënt naar het scherm krijgen in één grote blit. Een voorbeeld van zo'n spel is Doom, of Duke Nukem 3D, of vele andere.
Hiervoor zult u een enkele SDL_Texture willen die het scherm zal representeren. Laten we er nu een creëren voor ons 640x480 spel:
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
640, 480);
Dit komt neer op een texture op de GPU. De strategie is om elk frame te voltooien middels het uploaden van pixels naar deze texture, het texture te tekenen naar het venster, en deze flipt de tekening op het scherm. SDL_TEXTUREACCESS_STREAMING vertelt SDL dat de inhoud van deze texture regelmatig zal wijzigen.
Voorheen had u waarschijnlijk een SDL_Surface voor het scherm waarop uw applicatie tekende, vervolgens riep u SDL_Flip() aan om naar het scherm te schrijven. Nu kunt u een SDL_Surface creëren die altijd in RAM is in plaats van datgene gebruiken wat u zou hebben gekregen van SDL_SetVideoMode(), of enkel een blok met pixels malloc() om naar te schrijven. Idealiter schrijft u naar een buffer met RGBA pixels, maar als u een conversie moet uitvoeren, dat is ook goed.
extern Uint32 *mijnPixels; // misschien is dit een oppervlak->pixels, of een malloc()'d buffer, of wat dan ook.
Aan het einde van het frame, willen we als volgt uploaden naar het texture:
SDL_UpdateTexture(sdlTexture, NULL, mijnPixels, 640 * sizeof (Uint32));
Dit zal uw pixels uploaden naar het GPU geheugen. Die NULL kan een subregio zijn als u wilt prutsen met 'vuile rechthoeken', maar de kans is groot dat moderne apparatuur gewoon de hele framebuffer kan verwerken zonder veel moeite. Het laatste argument is de hoogte--het aantal bytes vanaf de start van een rij tot de volgende--en aangezien we een lineaire RGBA buffer hebben in dit voorbeeld, is het enkel 640 keer 4 (r,g,b,a).
Om nu dat texture op het scherm te krijgen:
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
Dat is alles. SDL_RenderClear() veegt de bestaande video framebuffer uit (in het geval, zeg, de Steam Overlay het laatste frame overschreef), SDL_RenderCopy() verplaatst de inhoud van de texture naar de video framebuffer (en dankzij SDL_RenderSetLogicalSize(), zal het zijn verschaald/gecentreerd alsof het beeldscherm 640x480 was), en SDL_RenderPresent() plaatst het op het scherm.
Als uw spel oppervlakken wil blitten naar het scherm
In dit scenario laadt uw SDL 1.2 spel een stel afbeeldingen van schijf naar een stel SDL_Surfaces, mogelijk proberende ze in video RAM te krijgen met SDL_HWSURFACE. U laadt deze eenmaal, en u blit ze telkens weer naar de framebuffer indien nodig, maar afgezien daarvan veranderen ze nooit. Een simpel 2D platformspel zou dit kunnen doen. Als u geneigd bent te denken over uw oppervlakken als "sprites," en niet buffers van pixels, dan is het volgende waarschijnlijk geschikt voor u.
U kunt individuele textures bouwen (oppervlakken die leven in het GPU geheugen) zoals we deden voor die ene grote texture:
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
mijnWijdte, mijnHoogte);
Dat doet wat je zou verwachten. We gebruiken SDL_TEXTUREACCESS_STATIC, want we gaan onze pixels eenmaal uploaden in plaats van telkens weer. Maar een gemakkelijkere oplossing is wellicht:
sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, mijnOppervlak);
Gebruik dit, en u laadt uw SDL_Surface zoals gebruikelijk, maar dan aan het einde maakt u een texture ervan. Heeft u eenmaal een SDL_Texture, dan kunt u de originele oppervlakken vrij maken.
Op dat moment had uw 1.2 spel een aantal SDL_Surfaces, welke het zou SDL_BlitSurface() naar het schermoppervlak om de uiteindelijke framebuffer samen te stellen, en tenslotte SDL_Flip() naar het scherm. Voor SDL 2.0, hebt u een aantal SDL_Textures, die u zult SDL_RenderCopy() naar uw Renderer om de uiteindelijke framebuffer samen te stellen, en tenslotte SDL_RenderPresent() naar het scherm. Zo simpel is het. Als deze textures nooit aangepast hoeven te worden, zult u mogelijk ondervinden dat uw framesnelheid zojuist ook door het dak is gegaan.
Als uw spel beide wil doen
Dingen worden ietwat gecompliceerder als u oppervlakken wilt blitten en individuele pixels wilt wijzigen in de framebuffer. Rondreizen--het teruglezen van gegevens van textures--kan pijnlijk kostbaar zijn; doorgaans wilt u altijd gegevens in één richting duwen. U bent waarschijnlijk het beste af, in dit geval, als u alles in software houdt tot de laatste push naar het scherm, dus we zullen de twee vorige technieken combineren.
Het goede nieuws: de 1.2 SDL_Surface API bestaat grotendeels nog steeds. Dus wijzig uw schermoppervlak van dit:
SDL_Surface *scherm = SDL_SetVideoMode(640, 480, 32, 0);
...naar dit...
// als al deze hex u afschrikt, raadpleeg SDL_PixelFormatEnumToMasks()!
SDL_Surface *scherm = SDL_CreateRGBSurface(0, 640, 480, 32,
0x00FF000,
0x0000FF00,
0x000000FF,
0xFF000000);
SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
640, 480);
...en blijf dingen blitten en pixels afstellen als voorheen, uw definitieve framebuffer samenstellende in deze SDL_Surface. Zodra u klaar bent om die pixels op het scherm te krijgen, doet u dit net als in ons eerste scenario:
SDL_UpdateTexture(sdlTexture, NULL, scherm->pixels, scherm->hoogte);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
Merk op dat een texture creëren zowel kostbaar als een beperkte hulpbron kan zijn: roep niet elk frame SDL_CreateTextureFromSurface() aan. Stel een texture in en een oppervlak, en werk eerstgenoemde met laatstgenoemde bij.
De Render API heeft meer mogelijkheden, waarvan sommige mogelijk in staat zijn brontekst van uw applicatie te vervangen: verschalen, lijntekenen, enz. Als u dit gedeelte leest omdat u simpele behoeften hebt die verder gaan dan oppervlakken blitten, bent u mogelijk in staat te stoppen met het porren van individuele pixels en kunt u alles verplaatsen naar de GPU, wat uw programma een significante snelheidsverhoging zal geven en waarschijnlijk uw brontekst zeer vereenvoudigt.
Andere Renderer API aandachtspunten
U kunt enkele simpele effecten bewerkstelligen met de render API zonder aan de slag te hoeven gaan met directe pixel manipulatie. Enkele van deze waren beschikbaar voor 1.2 oppervlakken.
Kleur alfa: SDL_Color nu bevat een vierde, alfa element. Uw 1.2 brontekst die zich bezighoudt met SDL_Colors kopieerde/zette die waarde mogelijk niet (die was genaamd unused). In 2.0 moet u dit wel doen.
Afa-vermenging: gebruik SDL_SetSurfaceAlphaMod en SDL_SetTextureAlphaMod in plaats van SDL_SetAlpha(). Alfa-vermenging op oppervlakken kan worden uitgeschakeld via SDL_SetSurfaceBlendMode() en op textures met SDL_SetTextureBlendMode().
Kleursleutel: Als u SDL_SetColorKey() aanroept, moet u SDL_TRUE meegeven in plaats van SDL_SRCCOLORKEY.
Kleurmodulering: Sommige renderers ondersteunen nu een globale kleurwijziging (brnC = brnC * kleur), bekijk SDL_SetTextureColorMod() voor meer informatie.
OpenGL
Als u OpenGL al rechtstreeks gebruikte, is uw migratie vrij simpel. Verander uw SDL_SetVideoMode() aanroep in SDL_CreateWindow() gevolgd door SDL_GL_CreateContext(), en uw SDL_GL_SwapBuffers() aanroep in SDL_GL_SwapWindow(venster). Al de daadwerkelijke aanroepen in de GL zijn precies hetzelfde.
Als u SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, x) gebruikte, dit is veranderd. Er is nu een SDL_GL_SetSwapInterval(x) aanroep, zodat u dit kunt veranderen op een bestaande GL context.
Merk op dat SDL 2.0 kan schakelen tussen venstermodus en fullscreen met OpenGL vensters zonder de GL context te verliezen (hoera!). Gebruik SDL_SetWindowFullscreen() hiervoor.
Invoer
Het goede nieuws is dat SDL 2.0 Unicode invoer mogelijk heeft gemaakt. Het slechte nieuws is dat het enkele kleine veranderingen zal behoeven in uw applicatie.
In 1.2, riepen veel applicaties die zich enkel druk maakten over VS Engels nog immer SDL_EnableUNICODE(1) aan, omdat het nuttig was om het teken te krijgen dat was verbonden met een toetsaanslag. Dit werkte niet goed zodra men zich buiten het Engels begaf, en het werkte al helemaal niet zodra men te maken kreeg met Aziatische talen.
Het blijkt dat i18n moeilijk is.
SDL heeft dit veranderd. SDL_EnableUNICODE() is verdwenen, en evenzo is SDL_Keysym's unicode veld. U krijgt niet langer tekeninvoer van SDL_KEYDOWN events. Gebruik SDL_KEYDOWN nu om het toetsenbord te behandelen als een 101-knop joystick. Tekstinvoer komt ergens anders vandaan.
Het nieuwe event is SDL_TEXTINPUT. Dit wordt teweeggebracht telkens als er nieuwe tekst is ingevoerd door de gebruiker. Merk op dat deze tekst misschien komt van toetsaanslagen, of het misschien komt van een soort van IME (dat is een chique manier om ingewikkelde, multi-teken tekst in te voeren). Dit event geeft volledige strings terug, die misschien één teken lang zijn, of verscheidene codeposities met multi-tekengegevens. Deze string is altijd in UTF-8 gecodeerd.
Als alles wat u belangrijk vindt is of de gebruiker een bepaalde toets indrukte, dat is nog altijd SDL_KEYDOWN, maar we hebben dit systeem gesplitst in twee delen vanaf 1.2: toetscodes en scancodes.
Scancodes zijn bedoeld om lay-out onafhankelijk te zijn. Beschouw dit als "de gebruiker drukte de Q toets in als het zou zijn op een VS QWERTY toetsenbord" ongeacht of dit daadwerkelijk een Europees toetsenbord is of een Dvorak toetsenbord of wat dan ook. De scancode is altijd dezelfde toetspositie.
Toetscodes zijn bedoeld om lay-out afhankelijk te zijn. Beschouw dit als "de gebruiker drukte de toets met het label 'Q' op zijn specifieke toetsenbord in."
Bijvoorbeeld, als u de toets indrukte die twee toetsen rechts is van CAPS LOCK op een VS QWERTY toetsenbord, zal het een scancode rapporteren van SDL_SCANCODE_S en een toetscode van SDLK_S. Dezelfde toets op een Dvorak toetsenbord zal een scancode rapporteren van SDL_SCANCODE_S en een toetscode van SDLK_O.
Merk op dat zowel toetscodes als scancodes nu 32 bits zijn, en een breed scala aan nummers gebruiken. Er is geen SDLK_LAST meer. Als uw programma een opzoektabel had met SDLK_LAST elementen, om te laveren tussen SDL toetsen en hetgeen uw applicatie intern wilde, dat is niet meer mogelijk. Gebruik in plaats daarvan een hashtabel. Een std::map bijvoorbeeld. Als u werkt met scancodes in plaats van toetscodes, is er SDL_NUM_SCANCODES, dat u kunt gebruiken voor matrixgrenzen. Diens waarde is momenteel 512.
SDLMod is nu SDL_Keymod en diens "META" toetsen (de "Windows" toetsen) worden nu de "GUI" toetsen genoemd.
SDL_GetKeyState() is hernoemd naar SDL_GetKeyboardState(). De resulterende matrix zou nu geïndexeerd moeten zijn op SDL_SCANCODE_* waarden (zie SDL_Scancode) in plaats van SDL_Keysym waarden.
Nu dan, wat betreft muisinvoer.
De eerste verandering, eenvoudigweg, is dat het muiswiel niet langer een knop is. Dit was een historische fout die we hebben gecorrigeerd in SDL 2.0. Kijk of er SDL_MOUSEWHEEL events zijn. Wij ondersteunen zowel verticale als horizontale wieltjes, en sommige platformen kunnen tevens twee-vinger scrollen op een trackpad afhandelen als wielinvoer. U zult niet langer SDL_BUTTONDOWN events ontvangen voor muiswieltjes, en knoppen 4 en 5 zijn nu echte muisknoppen.
Als uw spel de muis voor altijd moet rollen in één richting, bijvoorbeeld om een speler in een FPS rond te laten draaien zonder de muis de rand van het scherm te laten raken en te stoppen, verborg u waarschijnlijk de muiscursor en greep u de invoer:
SDL_ShowCursor(0);
SDL_WM_GrabInput(SDL_GRAB_ON);
In SDL2 werkt dit ietwat anders. U roept aan...
SDL_SetRelativeMouseMode(SDL_TRUE);
...en SDL doet de rest.
Events
SDL_PushEvent() geeft nu 1 terug bij succes in plaats van 0.
Events mask worden nu gespecificeerd middels bereiken:
SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_MOUSEBUTTONDOWN));
wordt:
SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONDOWN);
Geluid
Het goede nieuws voor geluid is dat, met één uitzondering, het volledig achterwaarts compatibel is met 1.2. Als u de nieuwe mogelijkheden wilt, ze zijn voor u beschikbaar, maar u zult waarschijnlijk gewoon zonder ze compileren en draaien.
Die ene heel belangrijke uitzondering: De geluid-callback begint NIET meer met een geheel geïnitialiseerde buffer. U moet in alle gevallen volledig schrijven naar de buffer. Als u niet genoeg geluid hebt, dan moet uw callback stilte schrijven. Als u dit nalaat zult u herhaald geluid horen, of wellicht verstoord geluid. Als u het oude gedrag wilt herstellen van onvoorwaardelijk initialiseren van de buffer, plaats dan gewoon een SDL_memset(stream, 0, len) bij aanvang van uw callback.
Joysticks
Joystick events verwijzen nu naar een SDL_JoystickID. Dit is omdat SDL 2.0 kan omgaan met het komen en gaan van joysticks, aangezien apparaten worden aangesloten en uitgetrokken gedurende de levensduur van uw spel, dus de inhoudsopgave in de apparatenlijst die 1.2 gebruikt zou zinloos zijn doordat de beschikbare apparatenlijst verandert.
Om een SDL_JoystickID te krijgen voor uw geopende SDL_Joystick*, roept u aan:
SDL_JoystickID mijnID = SDL_JoystickInstanceID(mijnGeopendeStick);
En vergelijk het joystick events' which veld met mijnID. Als u geen gebruik maakt van de gebeurteniswachtrij voor joysticks, werken SDL_JoystickGetAxis() en dergelijke net als bij SDL 1.2.
U moet ook de nieuwe Game Controller API raadplegen, aangezien die cool is, en wellicht sparde u veel met de 1.2 API dat deze nieuwe brontekst netter zou kunnen oplossen. U kunt het vinden in SDL_gamecontroller.h. De Game Controller API integreert heel mooi met Steam Big Picture Mode: u krijgt automatische configuratie van de meeste controllers, en een mooie UI als u het manueel moet configureren. In elk geval geeft Steam deze configuratie door aan uw SDL applicatie.
Ondersteuning voor de oudere joystick API (/dev/input/js*) voor Linux is geschrapt uit SDL2. SDL2 ondersteunt alleen de nieuwe events API (/dev/input/event*) voor joysticks. Deze events zijn doorgaans niet leesbaar voor normale gebruikersaccounts, dus zelfs als joysticks zijn aangesloten zult u er waarschijnlijk geen hebben gedetecteerd. Dit is iets dat eindgebruikers voor zichzelf moeten configureren.
Threads
SDL_KillThread() is verdwenen. Het was nimmer veilig of betrouwbaar. De beste vervanging is om een vlag te zetten die een thread vertelt dat het dient te stoppen. Die thread moeten met enige regelmaat de vlag controleren, en dan roept de "killing" thread SDL_WaitThread() aan om op te ruimen.
SDL_CreateThread() verwacht nu een extra parameter, een naam voor de thread, die kan worden gebruikt door debuggers om het te identificeren. Als het u niet kan schelen, voeg dan gewoon een extra NULL toe aan uw functie-aanroep.
Audio-cd's
De 1.2 cd API is volledig verdwenen. Er is geen vervanging. De kans is groot dat u op dit moment uw muziek niet verzendt als cd-audiosporen op een schijf, als u überhaupt een schijf verzendt. U kunt Ogg Vorbis gebruiken of een ander audiobestandsformaat voor muziek, waarvan er vele worden verstrekt door SDL_mixer.
Dode platformen
We hebben een stel oude platformen eruit gerukt, zoals OS/2 en Mac OS 9. Het is gemakkelijker om een overzicht te geven van degene die we nog ondersteunen: Windows (XP en nieuwer), Linux, Mac OS X, iOS, Android. In de traditie van SDL zijn er andere platformen die werken maar niet zwaar ondersteund worden, zoals Haiku en Sony PSP. We zullen elk platform toevoegen waarvoor iemand patches stuurt, maar het leek alsof het tijd was om afscheid te nemen van een aantal oude vrienden bij de verhuizing naar de nieuwe versie.
Mobiele platformen
Er zijn, jarenlang, onofficiële ports geweest van SDL 1.2 naar iOS en Android. SDL ondersteunt deze platformen nu rechtstreeks, en de 2.0 API is veel beter geschikt voor ze. De meeste adviezen die u elders in dit document kreeg zijn van toepassing, maar er is een aantal andere dingen vermeldenswaardig.
Om te beginnen, er zijn bepaalde events die alleen van toepassing zijn op mobiele apparaten, of beter gezegd, van toepassing zijn op de manier waarop OSen van mobiele apparaten neigen te werken in een post-iPhone wereld. Oorspronkelijk probeerden we deze te koppelen aan de bestaande SDL events (zoals "uw applicatie gaat naar de achtergrond" wordt behandeld als een bureaubladvenster dat focus verliest), maar er is een meer urgente zaak: de meeste van deze events behoeven een onmiddellijke reactie, en als de applicatie er geen geeft, zal het OS uw applicatie sluiten.
Derhalve hebben we nieuwe SDL events toegevoegd voor enkele Android en iOS bijzonderheden, maar u moet een SDL event filter instellen om ze te vangen zodra het OS ze meldt, want wachten op uw volgende SDL_PollEvent() lus zal te laat zijn.
Bijvoorbeeld, er is SDL_APP_WILLENTERBACKGROUND, dat is iOS's applicationWillResignActive(), en als u tekent naar het scherm nadat dit event binnenkomt, eindigt iOS uw proces. U wilt deze dus onmiddellijk afvangen:
int SDLCALL mijnEventFilter(void *gebruikersgegevens, SDL_Event * event)
{
if (event->type == SDL_APP_WILLENTERBACKGROUND) {
// resources vrijmaken, TEKEN NIET MEER totdat u weer in de voorgrond bent!
}
// enz
return 1;
}
// ergens bij het opstarten...
// dit roep mijnEventFilter(gegevens, event) aan zodra event wordt gegenereerd.
SDL_AddEventWatch(mijnEventFilter, gegevens);
Ten tweede, er zijn nu echte touch events, in plaats van te proberen dit te koppelen aan muisinvoer. U kunt touches volgen, meerdere vingers, en zelfs ingewikkelde gebaren. U wilt die waarschijnlijk gebruiken. Raadpleeg SDL_touch.h voor een lijst met die functies, en zoek naar SDL_Finger* in SDL_events.h.
Er is een handvol andere mobiel-vriendelijke functies, zoals SDL_StartTextInput(), die het virtueel toetsenbord zal tonen. Maak gebruik ervan.
Bovendien zijn er ook Android en iOS specifieke functies, om u toegang te geven tot platform-specifieke mogelijkheden die niet zinvol zouden zijn in een algemene API. Raadpleeg SDL_system.h voor een lijst van deze functies.
RWops
SDL_RWread() en SDL_RWwrite() geven nu 0 terug bij een fout in plaats van -1.
Als u uw eigen SDL_RWops implementatie schreef, de functie-signatures zijn veranderd. Functies gebruiken nu Sint64 en size_t in plaats van int dus ze kunnen werken met grote bestanden. In veel gevallen kunt u gewoon uw functie-signatures actualiseren en blijven werken als voorheen, maar als u aanliep tegen deze beperkingen zou u blij kunnen zijn een oplossing te hebben. Aangeroepen applicaties moeten weten dat de geretourneerde waarden zijn veranderd.
Er is nu ook een size-methode voor RWops. Dit laat een RWops de grootte rapporteren van de stream zonder de applicatie te moeten laten zoeken naar nul bytes vanaf het einde; met andere woorden, u kunt een totale grootte rapporteren voor streams waarin niet gezocht kan worden. Voor streams waarbij zelfs voorgaande niet werkt, kunt u nog immer -1 teruggeven.
Add-on bibliotheken
De officiële extensies SDL_image, SDL_ttf, SDL_mixer en SDL_net hebben een versie die zich toelegt op SDL 2.0: SDL2_image, SDL2_ttf, SDL2_mixer en SDL2_net. Het kan nodig zijn om ze te downloaden van de mercurial repository's voor de recente correcties. Vervolgens, vanzelfsprekend, zult u moeten linken bijv. SDL2_image, niet SDL_image, om uw programma te compileren.
Deze bibliotheken zullen 1.2 in de toekomst niet ondersteunen, en elke compatibiliteit met 1.2 zal waarschijnlijk op enig moment verdwijnen uit nieuwere versies.
SDL_gfx kan ook worden gecompileerd met 2.0 vanaf versie 2.0.21 (mei 2010).
Samenvatting van enkele hernoemde of vervangen dingen
Een kort spiekbriefje waar enkele van de oude functies en andere dingen heen zijn gegaan:
SDL_SetVideoMode(): gebruik SDL_CreateWindow() in de plaats (samen met SDL_CreateRenderer() als u klassieke 2D rendering wilt gebruiken en niet OpenGL)
SDL_ListModes(): gebruik SDL_GetDisplayMode()/SDL_GetNumDisplayModes() in de plaats
SDL_UpdateRect()/SDL_Flip(): gebruik SDL_RenderPresent() in de plaats
SDL_Surface/2D rendering: oppervlakken bestaan nog steeds, maar het wordt aanbevolen dat u in plaats van SDL_Surfaces waar mogelijk SDL_Textures gebruikt met een 2D geaccelereerde renderer (SDL_CreateRenderer())
SDL_VideoInfo: gebruik SDL_GetRendererInfo()/SDL_GetRenderDriverInfo() in de plaats
SDL_GetCurrentVideoDisplay(): gebruik SDL_GetWindowDisplayIndex() in de plaats
SDL_VIDEORESIZE event: het nieuwe equivalent is SDL_WINDOWEVENT_RESIZE
Andere dingen
Er is een enorme hoeveelheid van nieuwe en interessante functionaliteiten in SDL 2.0 waarvan 1.2 niet eens kon dromen. We hebben hier alleen geprobeerd uit te leggen wat u mogelijk moet doen om uw 1.2 programma draaiend te krijgen met 2.0, maar u zou de documentatie moeten verkennen voor dingen die u misschien altijd wenste en waarmee u het, tot nu toe, zonder moest doen. Bijvoorbeeld, elk spel dat ik ooit omzette bevatte uiteindelijk een berichtvenster-functie die er als volgt uitzag:
#if GEBRUIK_SDL
fprintf(stderr, "BRTVENSTER: %s\n%s\n", titel, tekst); // ach ja.
#endif
Nu is er SDL_ShowSimpleMessageBox(). Graag gedaan!
Als u vooruit sprong naar dit gedeelte, ga terug en bekijk al de nieuwe mogelijkheden in het overzicht!
