- Notifications
You must be signed in to change notification settings - Fork70
🎮 Simple, open-source 2D graphics for everyone
License
simple2d/simple2d
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Simple 2D is a small, open-source graphics engine providing essential 2D drawing, media, and input capabilities. It's written in C and works across many platforms, creating native windows and interacting with hardware usingSDL while rendering content withOpenGL.
Please note this README will be continuously updated as new features are added, bugs are fixed, and other changes are made.View the release notes for a link to that version's documentation.
Open an issue on GitHub if you encounter any problems, have a feature request, or simply want to ask a question. Learn more aboutcontributing below.
Simple 2D supports all major operating systems and hardware platforms, and is tested on the latest releases of macOS, iOS, tvOS, Windows, Linux, and Raspbian on the Raspberry Pi.
To install thelatest release...
UseHomebrew:
brew tap simple2d/tapbrew install simple2d
The Homebrew formula above will also install the iOS and tvOS frameworks to/usr/local/Frameworks/Simple2D by default. After installing, run thesimple2d simulator command to see available options for interacting with the iOS and tvOS simulators. Runsimple2d build to learn how to build Xcode projects with the iOS and tvOS SDKs. Example Xcode projects can be found in thedeps repository.
Download the Windows installer for Visual C++ or MinGW.
For MinGW, we recommend using anMSYS2 environment (also available onChocolatey) along with a MinGW 64-bit command prompt (usuallymingw64.exe). Simple 2D can also be installed on MinGW using the Linux instructions below.
Run thesimple2d.sh Bash script. Everything will be explained along the way and you'll be prompted before any action is taken. To run the script from the web, paste this snippet in your terminal:
url='https://raw.githubusercontent.com/simple2d/simple2d/master/bin/simple2d.sh'; which curl> /dev/null&& cmd='curl -fsSL'|| cmd='wget -qO -'; bash<($cmd$url) install
Simple 2D supports ARM platforms running Linux, like theRaspberry Pi. Since most Linux distributions have SDL packages configured for traditional desktop platforms, the install script will compile SDL from source when ARM is detected, disabling windowing systems (like X11) and OpenGL (forcing OpenGL ES instead).
Once installed, use thesimple2d command-line utility to update Simple 2D, check for issues, output the libraries needed to compile applications, and more. Simply runsimple2d to see all available commands and options.
Alternatively, you can compile and install Simple 2D from source. First clone this repo using:
git clone --recursive https://github.com/simple2d/simple2d.git
To keep the size of this repository small,Git submodules are used to referencetest media anddependencies. The--recursive flag ensures submodules are initialize and updated when this repo is cloned. If you happened to clone this repo without the--recursive flag, you can still initialize and update submodules with:
git submodule initgit submodule update --remote
Update these submodules at any time usinggit submodule update --remote
Next, build and install on Unix-like systems, including Windows using MinGW, by running:
make&& make installOn Windows using Visual C++, open a 64-bit Visual Studio command prompt and run:
nmake /f NMakefile all install
Note that on macOS and Linux, the makefile will not check for or install dependencies, unlike installing via Homebrew or thesimple2d.sh script, respectively. Dependencies for Windows, supporting both Visual C++ and MinGW,are included in this repo (referenced by thedeps submodule) and installed by both makefiles.
On Windows using Visual C++, Simple 2D will be installed to%LOCALAPPDATA%\simple2d, so make sure to add that to your path (for example withset PATH=%PATH%;%LOCALAPPDATA%\simple2d). In all other cases, it will be installed to/usr/local/. On Windows using MinGW, make sure/usr/local/bin is in your path as well.
To build the release archives, which are attached asdownloads with each release, runmake release on macOS and Windows using MinGW, andnmake /f NMakefile release on Windows using Visual C++.
Simple 2D has several test programs to make sure everything is working as it should.
auto.c— A set of automated unit tests for the public interface.triangle.c— The "Hello Triangle" example in this README.testcard.c— A graphical card, similar toTV test cards, with the goal of ensuring visuals and inputs are working properly.audio.c— Tests audio functions with various file formats interpreted as both sound samples and music.controller.c— Provides visual and numeric feedback of game controller input.triangle-ios-tvos.c— A modifiedtriangle.cdesigned for iOS and tvOS devices.
Runmake test, ornmake /f NMakefile test on Windows using Visual C++, to compile tests to thetest/ directory. The resulting executables will have the same name as their C source files. Since media paths are set relatively in these test programs, make sure tocd into thetest/ directory before running a test, for example:
# On Unix-like systemsmaketest&&cd test/&& ./testcard# On Windows using MinGWmaketest&cd test\& testcard.exe# On Windows using Visual C++nmake /f NMakefiletest&cd test\& testcard.exe
Each test also has a makefile target, so you can build and run tests using, for example,make test testcard. Or, conveniently uninstall everything, rebuild Simple 2D and tests from source, and run tests usingmake rebuild <name_of_test>, for example:
# Rebuild and run `auto.c` then `testcard.c`...# ...on Unix-like systems and Windows using MinGWmake rebuild auto testcard# ...on Windows using Visual C++nmake /f NMakefile rebuild auto testcard
To run the iOS and tvOS tests, first runmake frameworks && make install-frameworks to build and install the iOS and tvOS frameworks. Next, runmake ios to run the test in an iOS simulator andmake tvos to run in a tvOS Simulator.
Making 2D apps is simple! Let's create a window and draw a triangle...
#include<simple2d.h>voidrender() {S2D_DrawTriangle(320,50,1,0,0,1,540,430,0,1,0,1,100,430,0,0,1,1 );}intmain() {S2D_Window*window=S2D_CreateWindow("Hello Triangle",640,480,NULL,render,0 );S2D_Show(window);return0;}
Save the code above to a file calledtriangle.c and compile it by runningsimple2d build triangle.c on the command line (in MinGW, run this in a Bash prompt). Now run the app using./triangle on macOS and Linux, ortriangle.exe on Windows, and enjoy your stunning triangle in a 640x480 window at 60 frames per second!
Thesimple2d build command is a helpful shortcut for compiling a single source file. Of course, you can also use a compiler directly, for example on Unix-like systems:
cc triangle.c`simple2d --libs` -o triangleAnd on Windows using Visual C++ in a developer command prompt:
cl triangle.c /I %LOCALAPPDATA%\simple2d /link /LIBPATH %LOCALAPPDATA%\simple2d\simple2d.lib /SUBSYSTEM:CONSOLE# as a PowerShell commandiex"cl triangle.c$(simple2d --libs)"
Let's learn about structuring applications for 2D drawing and more.
All rendered content, input, and sound is controlled by the window, so creating a window is the first thing you'll do. Start by declaring a pointer to aS2D_Window structure and initialize it usingS2D_CreateWindow().
S2D_Window*window=S2D_CreateWindow("Hello World!",// title of the window800,600,// width and heightupdate,render,// callback function pointers (these can be NULL)0// flags);
To set the window's width and height the same as the display's, useS2D_DISPLAY_WIDTH andS2D_DISPLAY_HEIGHT for those values, respectively.
The window flags can be0 or any one of the following:
S2D_RESIZABLE// allow window to be resizedS2D_BORDERLESS// show window without a borderS2D_FULLSCREEN// show window at fullscreenS2D_HIGHDPI// enable high DPI mode
Flags can also be combined using the bitwise OR operator, for example:S2D_RESIZABLE | S2D_BORDERLESS
The size of the viewport, the area where graphics are drawn in the window, can be set independently of the window size like so:
window->viewport.width=400;window->viewport.height=300;
The viewport has various scaling modes, such asS2D_FIXED (viewport stays the same size as the window size changes),S2D_EXPAND (viewport expands to fill the window when resized),S2D_SCALE (the default, where the viewport scales proportionately and is centered in the window), orS2D_STRETCH (viewport stretches to fill the entire window). Set the mode like this:
window->viewport.mode=S2D_FIXED;
Before showing the window, these attributes can be set:
window->vsync= false;// set the vertical sync, true by defaultwindow->icon="app.png";// set the icon for the window
Once your window is ready to go, show it using:
S2D_Show(window);
Any time before or during the window is being shown, these attributes can be set:
// Cap the frame rate, 60 frames per second by defaultwindow->fps_cap=30;// Set the window background color, black by defaultwindow->background.r=1.0;window->background.g=0.5;window->background.b=0.8;window->background.a=1.0;
Callback functions can also be changed any time — more on that below. Many values can be read from theS2D_Window structure, see thesimple2d.h header file for details.
The window icon can be changed using:
S2D_SetIcon(window,"new_icon.png");
Take a screenshot of the window in PNG format, providing a file path:
S2D_Screenshot(window,"./screenshot.png");
When you're done with the window, free it using:
S2D_FreeWindow(window);
The window loop is where all the action takes place: the frame rate is set, input is handled, the app state is updated, and visuals are rendered. You'll want to declare two essential functions which will be called by the window loop:update() andrender(). Like a traditional game loop,update() is used for updating the application state, andrender() is used for drawing the scene. Simple 2D optimizes both functions for performance and accuracy, so it's good practice to keep those updating and rendering tasks separate.
The update and render functions should look like this:
voidupdate() {/* update your application state */ }voidrender() {/* draw stuff */ }
Remember to add these function names when callingS2D_CreateWindow() (see"The window" section above for an example).
To exit the window loop at any time, use:
S2D_Close(window);
All kinds of shapes and textures can be drawn in the window. Learn about each of them below.
Several geometric shapes are available, like triangles, quadrilaterals (which rectangles and squares can be made from), lines, and circles. Every shape contains vertices, that is, places where two lines meet to form an angle (a triangle has three, for example). For each vertex of a triangle and quadrilateral, there are six values which need to be set: thex andy coordinates, and four color values. Lines have two vertices, although colors for each corner can be set. Circles have a single center point and color that can be set. When vertices have different color values, the space between them are blended in a gradient.
The shorthand for the examples below are:
x=thexcoordinatey=theycoordinate// Color range is from 0.0 to 1.0r=redg=greenb=bluea=alpha (opacity)
Using this notation,x2 would be the secondx coordinate, andb2 would be the blue value at that vertex.
To draw a triangle, use:
S2D_DrawTriangle(x1,y1,r1,g1,b1,a1,x2,y2,r2,g2,b2,a2,x3,y3,r3,g3,b3,a3);
To draw a quadrilateral, use:
S2D_DrawQuad(x1,y1,r1,g1,b1,a1,x2,y2,r2,g2,b2,a2,x3,y3,r3,g3,b3,a3,x4,y4,r4,g4,b4,a4);
To draw a line, use:
S2D_DrawLine(x1,y1,x2,y2,width,r1,g1,b1,a1,r2,g2,b2,a2,r3,g3,b3,a3,r4,g4,b4,a4);
To draw a circle, use:
S2D_DrawCircle(x,y,radius,sectors,r,g,b,a);
Images in many popular formats, like JPEG, PNG, and BMP can be drawn in the window. Unlike shapes, images need to be read from files and stored in memory. Simply declare a pointer to anS2D_Image structure and initialize it usingS2D_CreateImage() providing the file path to the image.
S2D_Image*img=S2D_CreateImage("image.png");
If the image can't be found, it will returnNULL.
Once you have your image, you can then change itsx, y position like so:
img->x=125;img->y=350;
Change the size of the image by adjusting its width and height:
img->width=256;img->height=512;
Rotate the image like so:
// Angle should be in degrees// The last parameter is the point the image should rotate around, either:// S2D_CENTER, S2D_TOP_LEFT, S2D_TOP_RIGHT, S2D_BOTTOM_LEFT, or S2D_BOTTOM_RIGHTS2D_RotateImage(img,angle,S2D_CENTER);// Or, set a custom point to rotate aroundimg->rx=50;img->ry=75;// Set the rotation angle directlyimg->rotate=90;
You can also adjust the color of the image like this:
// Default is 1.0 for each, a white color filterimg->color.r=1.0;img->color.g=0.8;img->color.b=0.2;img->color.a=1.0;
Finally, draw the image using:
S2D_DrawImage(img);
Since images are allocated dynamically, free them using:
S2D_FreeImage(img);
Sprites are special kinds of images which can be used to create animations. To create a sprite, declare a pointer to anS2D_Sprite structure and initialize it usingS2D_CreateSprite() providing the file path to the sprite sheet image.
S2D_Sprite*spr=S2D_CreateSprite("sprite_sheet.png");
If the sprite image can't be found, it will returnNULL.
Clip the sprite sheet to a single image by providing a clipping rectangle:
S2D_ClipSprite(spr,x,y,width,height);
Thex, y position of the sprite itself can be changed like so:
spr->x=150;spr->y=275;
Change the size of the sprite by adjusting its width and height:
spr->width=100;spr->height=100;
Rotate the sprite like so:
// Angle should be in degrees// The last parameter is the point the sprite should rotate around, either:// S2D_CENTER, S2D_TOP_LEFT, S2D_TOP_RIGHT, S2D_BOTTOM_LEFT, or S2D_BOTTOM_RIGHTS2D_RotateSprite(spr,angle,S2D_CENTER);// Or, set a custom point to rotate aroundspr->rx=50;spr->ry=75;// Set the rotation angle directlyspr->rotate=90;
You can also adjust the color of the sprite image like this:
// Default is 1.0 for each, a white color filterspr->color.r=1.0;spr->color.g=0.8;spr->color.b=0.2;spr->color.a=1.0;
Finally, draw the sprite using:
S2D_DrawSprite(spr);
Since sprites are allocated dynamically, free them using:
S2D_FreeSprite(spr);
Text is drawn much like images. Start by finding your favorite OpenType font (with a.ttf or.otf file extension), then declare a pointer to aS2D_Text structure and initialize it usingS2D_CreateText() providing the file path to the font, the message to display, and the size.
S2D_Text*txt=S2D_CreateText("vera.ttf","Hello world!",20);
If the font file can't be found, it will returnNULL.
You can then change thex, y position of the text, for example:
txt->x=127;txt->y=740;
Rotate the text like so:
// Angle should be in degrees// The last parameter is the point the text should rotate around, either:// S2D_CENTER, S2D_TOP_LEFT, S2D_TOP_RIGHT, S2D_BOTTOM_LEFT, or S2D_BOTTOM_RIGHTS2D_RotateText(txt,angle,S2D_CENTER);// Or, set a custom point to rotate aroundtxt->rx=50;txt->ry=75;// Set the rotation angle directlytxt->rotate=90;
Change the color of the text like this:
// Default is 1.0 for each, a white color filtertxt->color.r=0.5;txt->color.g=1.0;txt->color.b=0.0;txt->color.a=0.7;
Finally, draw the text using:
S2D_DrawText(txt);
You can also change the text message at any time:
S2D_SetText(txt,"A different message!");// Format text just like `printf`S2D_SetText(txt,"Welcome %s!",player);
Since text is allocated dynamically, free them using:
S2D_FreeText(txt);
Simple 2D supports a number of popular audio formats, including WAV, MP3, Ogg Vorbis, and FLAC. There are two kinds of audio concepts: sounds and music. Sounds are intended to be short samples, played without interruption, like an effect. Music is for longer pieces which can be played, paused, stopped, resumed, and faded out, like a background soundtrack.
Create a sound by first declaring a pointer to aS2D_Sound structure and initialize it usingS2D_CreateSound() providing the path to the audio file.
S2D_Sound*snd=S2D_CreateSound("sound.wav");
If the audio file can't be found, it will returnNULL.
Play the sound like this:
S2D_PlaySound(snd);
You can get and set the volume of a sound like so:
intvolume=S2D_GetSoundVolume(snd);S2D_SetSoundVolume(snd,50);// set volume 50%
In addition, get and set the volume of all sounds like this, where the volume is a range between 0 (softest) and 100 (loudest):
intvolume=S2D_GetSoundMixVolume();S2D_SetSoundMixVolume(50);// set volume 50%
Since sounds are allocated dynamically, free them using:
S2D_FreeSound(snd);
Similarly, create some music by declaring a pointer to aS2D_Music structure and initialize it usingS2D_CreateMusic() providing the path to the audio file.
S2D_Music*mus=S2D_CreateMusic("music.ogg");
If the audio file can't be found, it will returnNULL.
Play the music like this, where the second parameter is a boolean value indicating whether the music should be repeated:
S2D_PlayMusic(mus, true);// play on a loop
Only one piece of music can be played at a time. The following functions for pausing, resuming, getting and setting volume, stopping, and fading out apply to whatever music is currently playing:
S2D_PauseMusic();S2D_ResumeMusic();S2D_StopMusic();intvolume=S2D_GetMusicVolume();S2D_SetMusicVolume(50);// set volume 50%// Fade out over 2000 milliseconds, or 2 secondsS2D_FadeOutMusic(2000);
Since music is allocated dynamically, free them using:
S2D_FreeMusic(mus);
Simple 2D can capture input from just about anything. Let's learn how to grab input events from the mouse, keyboard, and game controllers.
There are three types of keyboard events captured by the window: when a key is pressed down, a key is being held down, and a key is released. When a keyboard event takes place, the window calls itson_key() function.
To capture keyboard input, first define theon_key() function and read the event details from theS2D_Event structure, for example:
voidon_key(S2D_Evente) {// Check `e.key` for the key being interacted withswitch (e.type) {caseS2D_KEY_DOWN:// Key was pressedbreak;caseS2D_KEY_HELD:// Key is being held downbreak;caseS2D_KEY_UP:// Key was releasedbreak; }}
Then, attach the callback to the window:
window->on_key=on_key;
The cursor position of the mouse or trackpad can be read at any time from the window. Note that the top, left corner is the origin,(0, 0).
window->mouse.x;window->mouse.y;
To capture mouse button input, first define theon_mouse() function and read the event details from theS2D_Event structure, for example:
// `e.button` can be one of:// S2D_MOUSE_LEFT// S2D_MOUSE_MIDDLE// S2D_MOUSE_RIGHT// S2D_MOUSE_X1// S2D_MOUSE_X2voidon_mouse(S2D_Evente) {switch (e.type) {caseS2D_MOUSE_DOWN:// Mouse button was pressed// Use `e.button` to see what button was clicked// Check `e.dblclick` to see if was a double clickbreak;caseS2D_MOUSE_UP:// Mouse button was released// Use `e.button` to see what button was clicked// Check `e.dblclick` to see if was a double clickbreak;caseS2D_MOUSE_SCROLL:// Mouse was scrolled// Check `e.direction` for direction being scrolled, normal or inverted:// S2D_MOUSE_SCROLL_NORMAL// S2D_MOUSE_SCROLL_INVERTED// Check `e.delta_x` and `e.delta_y` for the difference in x and y positionbreak;caseS2D_MOUSE_MOVE:// Mouse was moved// Check `e.delta_x` and `e.delta_y` for the difference in x and y positionbreak; }}
Then, attach the callback to the window:
window->on_mouse=on_mouse;
Hide the cursor over the window (and show it again) using:
S2D_HideCursor();S2D_ShowCursor();
All game controllers are automatically detected, added, and removed. There are two types of events captured by the window: axis motion and button presses. When a button is pressed or a joystick moved, the window calls itson_controller() function. Buttons and axes are mapped to a generic Xbox controller layout.
To capture controller input, first define theon_controller() function and read the event details from theS2D_Event structure, for example:
voidon_controller(S2D_Evente) {// Check `e.which` for the controller being interacted withswitch (e.type) {caseS2D_AXIS:// Controller axis was moved// Use `e.axis` to get the axis, either:// S2D_AXIS_LEFTX, S2D_AXIS_LEFTY,// S2D_AXIS_RIGHTX, S2D_AXIS_RIGHTY,// S2D_AXIS_TRIGGERLEFT, S2D_AXIS_TRIGGERRIGHT,// or S2D_AXIS_INVALID// Use `e.value` to get the value of the axisbreak;// For the following button events, use `e.button`// to get the button pressed or released, which can be:// S2D_BUTTON_A, S2D_BUTTON_B, S2D_BUTTON_X, S2D_BUTTON_Y,// S2D_BUTTON_BACK, S2D_BUTTON_GUIDE, S2D_BUTTON_START,// S2D_BUTTON_LEFTSTICK, S2D_BUTTON_RIGHTSTICK,// S2D_BUTTON_LEFTSHOULDER, S2D_BUTTON_RIGHTSHOULDER,// S2D_BUTTON_DPAD_UP, S2D_BUTTON_DPAD_DOWN,// S2D_BUTTON_DPAD_LEFT, S2D_BUTTON_DPAD_RIGHT,// or S2D_BUTTON_INVALIDcaseS2D_BUTTON_DOWN:// Controller button was pressedbreak;caseS2D_BUTTON_UP:// Controller button was releasedbreak; }}
Then, attach the callback to the window:
window->on_controller=on_controller;
See thecontroller.c test for an exhaustive example of how to interact with game controllers.
You're certain to find controllers that don't yet have button mappings, especially if they're brand new. See thecommunity-sourced database of controller mappings for examples of how to generate mapping strings. Once you have the mapping string, you can register it usingS2D_AddControllerMapping(), or add several mappings from a file usingS2D_AddControllerMappingsFromFile() and providing the file path.
"Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains." —Steve Jobs
Despite the continuing advancements in computer graphics hardware and software, getting started with simple graphics programming isn't that easy or accessible. We're working to change that.
If you like the project, please consider contributing! Check out theopen issues for ideas, or suggest your own. We're always looking for ways to make the project more inviting and improve the developer experience on every platform. Don't worry if you're not an expert in C or graphics APIs — we'll be happy to walk you through it all.
If youare a hardcore C and OS hacker, you should seriously consider contributing toSDL so we can continue writing games without worrying about the platform details underneath. Take a look at the talks fromSteam Dev Days, especiallyRyan C. Gordon's talk onGame Development with SDL 2.0.
- Update dependencies
- Update SDL versions in
simple2d.sh - Make any updates to the
depsrepo (follow instructionsin the README), and rungit submodule update --remotein this repo to update the submodule
- Update SDL versions in
- Run tests on all supported platforms
- Update documentation to reflect the current API
- Update the Simple 2D version number in
simple2d.shandsimple2d.cmd, commit changes - Create Windows installers (for Visual C++ and MinGW) and Apple libraries using the
releasemake/nmake target - Create anew release in GitHub, with tag in the form
v#.#.#; attach Windows installers and Apple libraries to release notes - Update theHomebrew tap:
- Update formula with new release archive and frameworks resource URLs
- Calculate the new
sha256checksums for the release and frameworks archive, usingshasum -a 256 <file> - Run
brew audit --strict ./simple2d.rbto detect any issues with the formula - Test installation of the formula using
brew install ./simple2d.rb - Commit and push changes to the formula
- 🎉
Simple 2D was created byTom Black, who thought simple graphics programming was way too difficult and decided to do something about it.
Everything isMIT Licensed, so hack away.
Enjoy!
About
🎮 Simple, open-source 2D graphics for everyone
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Contributors10
Uh oh!
There was an error while loading.Please reload this page.