Bienvenue sur le site de la LibLapin.
Jetez un coup d'oeil en bas de la page pour choisir votre niveau de documentation en fonction de votre niveau avec la LibLapin.
Pour l'instant, c'est réglé sur 'Manuel complet'. Si c'est votre première fois avec la LibLapin, il vaudrait mieux choisir 'Débutant'.
De même, n'oubliez pas de préciser une version de la bibliothèque.
This first tutorial "Display and React" will teach you how
to generate a graphic output as you desire and to react
to basic user actions.
The first thing you need to know is that every bunny library
functions are present in:
#include <lapin.h>
The first step to get a graphic program is to create a window.
A window is a rectangle on screen that can have any size.
To open a window, the function bunny_start must be used.
The window is generally open all time during the program lifetime.
The window can be moved, resized, fullscreen, can request the focus
to the operating system.
The window is the main target for drawing and even when it is not
the immediate target, it always end on it.
As target for drawing, opening it does not means its inner graphics
are refreshed. To refresh it, and having its real content displayed,
the bunny_display function must be used.
By calling this function, a window will be created. You
will be responsible for the management of it right after
it is created: you must have a way to store it to use it
and close it when you do not need it anymore.
By default, the window is filled with a nice pink color.
This function display on screen what was before in the window graphic memory. This operation is quite expansive and should be done only when everything is drawn and ready.
This function close the sent window, and if it was fullscreen, it also restore the previous screen resolution. It is very important to use it well!
Here is a simple program which create a window, wait a little
and then exit:
The second step to get a graphic program is to manage the window
to get a program lifecycle.
In the previous part, we have created a simple program that open, wait
and close the window, but there was no interaction with the user. This time,
there will be one.
We will use several additionnal functions to do a new colorful program
that exit on demand, those functions are:
bunny_set_key_response, bunny_fill and bunny_loop.
This function allow you to define a function that will be called
when a key is pressed or released. The function will be automatically
called by a mechanism inside another function you will use: bunny_loop.
This function, which takes a t_bunny_buffer can be used on t_bunny_window
because t_bunny_window contains a t_bunny_buffer! This function, when used
on a window, will entirely fill the window with the sent color.
To give to bunny_fill a window, you can do it two ways:
  bunny_fill((t_bunny_buffer*)win);
or:
  bunny_fill(&win->buffer);
The second fashion is the one I will use in all tutorials.
This function is a huge part of the bunny library: it handles all events
the bunny library can handle, it is real time locked, that means you can
set a frequency and it will run this frequency on high speed machine like
on low speed machine (if performences are good enough) so your program
speed does not rely on the computer.
In this program, the bunny_loop will be useful to us because we will need
to handle key events. We set with bunny_set_key_response a request to
bunny_loop to call a function when it is needed.
Here is a simple program which create a window, exit on escape and change
color of window for any other key.
You know how to open, manage and close window, you know how to
handle simple events.
Drawing can be done on several kind of surfaces: the first
kind is pictures managed by graphic cards and the second one
pictures managed by CPU.
The first kind of picture is fast when doing clip works:
sprites, complex shapes, special effects.
The second kind of picture is fast when doing pixel per pixel works.
The first kind is mainly presented as t_bunny_picture in bunny library
and the second one t_bunny_pixelarray. In this tutorial, we will only
use t_bunny_picture because basics are easier.
t_bunny_pixelarray will be treated in specific chapters
which are designed for schoolarship usage and less purely informative.
This function allow you to define a function that will be called
when the mouse move. We will use this function to start drawing.
This function will return to us the mouse position on window.
This function allow you to define a function that will be called
when a mouse button is pressed or released.
We will use this function to register if the current left
mouse button is down or up.
This function will return to us the mouse button status.
This function will color a single pixel at the position you sent and with the color you sent.
Here is a simple program which trigger the drawing when the
left mouse button is pressed and draw when the mouse is moving.
You can exit this program with the right mouse button.
Now that you have learnt how to draw pixel, you will learn
how to draw lines and circle with bunny_set_line and bunny_set_circle,
on GPU side.
This time, the drawing will be automatic: we will simply
use events to exit the program.
The shape we will draw will be made of several lines and
circles in rotation, drawn recursively.
Because this tutorial talks about "dancing", then graphics on screen
will move! For this, we will learn how to use the real time clock of
the bunny library.
You will also learn how to display correctly in the bunny library:
you will not draw anywhere but in a single function which is called
under specific circumstances.
This tutorial will also show you a way to broadcast your
main data between different events.
This function will draw on target a single line from the position
in coordinates[0] to the position in coordinates[1],
starting from colors[0] and gradually arriving to
colors[1].
This function will draw on target a single circle with its
center at position coordinate and with its width and height
in radius and color in color. To draw a real circle
instead of an ovoid, radius.x must equal radius.y.
This function is guarantee to be averagely called at a given frequency.
The frequency is given throught the second parameter of the bunny_loop
(or bunny_loop_mw, we will say later) function. This is the "loop main function"
because of this. It exploits the real time clock of the bunny library.
This function is called when the program needs to refresh its display.
It is called if there is enough time at the end of the whole main loop
and a single time per loop.
What does that mean? It means if your program became very laggy a short
moment and a lot of calls to your loop function is made to catch up, then
no call to display will be made if there is not enough time, or a single
one if there is enough.
There is a security that prevent the screen from being frozen: even if
the main loop is really slow, there will always be at least one display
every twenty loops.
This program is a little more complex than simply drawing circle
and lines, in order to bring a little more fun. This paragraph will
explain to you what is going on. We will start with the main data
definition:
The loop function will be quite empty: the program does almost nothing
else than displaying things on screen, but it got a few off screen work too!
The animation progression is, for example, off screen, even if it has
to do with what will be displayed!
Understand this: loop function has to do with everything that
must be real time synchronized... if the animation progression
was outside, it may changed depending of machine performences!
The display function is where most of the work is made.
First, we fill the whole screen with a very transparent black (25% opacity only),
so everything on screen is not whipped directly must transit to black.
This is a quite cheap (on GPU) fashion to create trails.
The objective of the following part is to get a circle moving likes it is in 3D.
So, right after screen cleaning, we set two t_bunny_position structures,
one for the size of the circle and the other one the the position.
Without surprise, the center of the circle is the middle of the window.
The size of the circle will vary accordingly to the value of step inside
the main data structure. Using the cos or sin function with step will
generate a value between -1 and 1 that we will multiply with the maximum
space we can take inside the window without going out, consider its size
and the position of the circle.
Note that we use cos and sin so the size of the circle will
be altered in a way it look likes 3D. If we do not want this, simple use
cos or sin on both the computation of circle_size.x and
circle_size.y will keep the circle facing the user.
Ultimately, we call bunny_set_circle to draw our circle.
Here is the hardest part. In this part, we will draw wings on the disk part
of the circle.
We start by creating two arrays: an array of color, and an array of
position. We need them for calling bunny_set_line. Colors are set immediatly,
and the first coordinate is also set immediatly: all lines will start
from the center of the circle.
Additionnal, we set additional_step, a double which will be used
as loop index. The content of the loop will be useful to set to some values
to the second coordinate of the line.
Here is how we create those wings: we will draw circle rays going shorter
and shorter. When entering the loop, we set a first line going from
the center of the circle to the border of the circle, and then, another
rays softly shifted and shorter, and then another one, etc.
The cos/sin(2 * data->step + additional_step) is used to compute the angle
of the circle: As we want wings to turn, we need data->step because
it evolves constantly because of loop_function. Additionnaly, because we
need to have several lines shifted to create wings, we add it to
additional_step. The 2.3 coefficient is present to break the synchronicity
between the circle move and the wing move.
This call to cos/sin give a coefficient we will multiply by the circle
size to the wings scale follow the circle scale. By multiplying it by
(1 - additional_step), considering additional_step goes from 0 to 1,
it means additional lines will be shorter and shorted.
As you may notice, there is two calls to bunny_set_line: this is because
to create a single rays, two calls are needed in order to have a gradiant
from red on borders to black on center. So one line is drawn from a side
of the circle to the center, and another one from the opposite to the
circle.
Ultimately, we call bunny_display to refresh the screen output will all
our drawings and we exit the function.
Here is the full program. You may notice some parts were not explained
before: the key handling function and the main you may understand alone.
This chapter is quite important: sprites are often the fondation
video game programs. In this chapter, you will learn how to
edit a t_bunny_clipable to get what you wish on screen.
This chapter is not about t_bunny_sprite: if you want
to learn how to use them, go to Animate a sprite using sprites
tutorial.
Sprite sheets are pictures containing a single character with
different pose and that are supposed to be played one after
the other to make it animated. To do so, you will first need
a sprite sheet. We will use this one, download
it. The program you will make will display this sprite
moving on screen while being animated, in four direction.
This sprite contains two animation: the first one on the first line
contains only a single frame (so.. technically, it is not an animation).
The second one on the second line contains height frames.
To complete a little more, we will also learn a new event: the mouse
wheel event.
This function allows you to load a picture file like the sprite sheet we will use. It may returns NULL on error and the generated t_bunny_picture must be freed with bunny_delete_clipable.
The function that is useful to delete clipable.
This function is very important: it is the one that will draw your picture on the surface you want it to be: the window, most of times. Third third parameter is optional and can be set to NULL: in this case, the position field inside the clipable parameter will be used instead.
Get the frequency sent to bunny_loop. Should be used when trying
to compute speeds instead of pure arbitrary value. For example,
300.0 / bunny_get_frequency() if use to move an object on screen
will produce a double value that can be used each main loop. It means
300 pixel per seconds which is a really more convenient way to
write such a thing than an arbitrary 12 and of course it keeps
the same speed even if you change the loop frequency, which
is really better!
It means you can increase the bunny_loop frequency accordingly
to performances, to allow more frame per seconds.
This function returns an array which contains all keys status. It will
works only if a keyboard response is set. In our case, it is set
to catch the escape key and exit the program.
The purpose of this function is to get status instead of events like
key pressed or released. It is convienent to use, especially in the
main loop of your program.
This function allow you to define a function that will be called when a mouse wheel is scrolled. We will use it to scale the sprite.
This is the main data that will be sent to all events. You
can find the window inside it, the picture containing the sprite
you have downloaded before and animation_frame.
I indicates which animation frame will be displayed: it is a
double because we need it to be able to evolve with a step like
10.0 / bunny_get_frequency(), that means "10 frames per second"
which may not be an integer... but it is used as an integer when
it came to picking up a specific frame, as we will see later.
Let it start with the display function of the program. It is quite
straightforward:
Here is the beginning of the main, the part when the sprite will
be initialized. The picture is first loaded and then fields are
sets to specific values.
clip_height and clip_width are purely linked to the sprite
itself: as you will see by opening the sprite sheet, a single
character is 107*100 pixels.
The origin field is by default on the top left corner. Sometimes
it is convient, sometimes not. Right now, we are setting the
origin to the center of the clip (remember: the clip is the part
of the picture that is displayed when calling bunny_blit) so
if we draw the sprite at the center of the window, the center of the
clip will be at the center of the window, not the top left corner.
The position field is by default 0, 0. We set it to the center
of the window.
Other fields are keeping their original value: 0 for rotation.
1, 1 for scale, 0 for clip_x_position and 0 for clip_y_position.
Color mask stay white so all sprite colors are unaltered.
At the end, we set animation_frame from the main data to 0,
se when we will animate the sprite, it will start with the first
frame.
The set_clip_to_set is a small sub procedure called in the loop_function
and that factorize some operations:
It takes the main data structure and set the sprite clip to the
appropriate frame. To do so, it use animation_frame from the main
data, casted as an integer, and use the modulo operator to keep it
in [0; 8[ and always growing. By multiplying this integer after that by
clip_width of the sprite, we positionate the clip on the right frame
of the current animation.
We set to the sent animation the clip_y_position accordingly to
the specification of the sprite sheet: by multiplying animation
by clip_height, we set the right line for the requested animation.
The rotation field may appeir strange to you: The sub procedure
receives a rotation value but apply it only if it is a multiple of 90.
This is only for conveniance, this is not animation related: it is made
so when someone want to call the subprocedure without changing the
rotation, this person will be able to do it simply by sending a fitting value.
The animation_frame is increased by a value which will make it go
as fast as 18 frames per seconds.
This is the main loop of the program. Every arrow keys are tested
and provoke reactions of your program.
We enter the first if if the left arrow key is currently pressed:
it means the character must walk to the left side of the screen.
So we call the sub procedure set_clip_to_set with the main data,
the animation number (1 being the line on the sprite sheet: the walking animation
in our case) and the angle of the sprite rotation we need.
Because the sprite in our sprite sheet is looking up, when going left,
we need it to being rotated by -90 degrees.
After that, the effectively change the sprite position on screen by
removing a value which will make it go as fast as 100 pixels per seconds.
Note that in computing, the coordinate system place the origin on the top
left corner of the window/screen, goes from left to right on X and from top
to bottom on Y. It is not like in mathematics, it may be strange at the
beginning, but you will get accustomed to. I do not recommand making
abstraction to change this: that would lost any computer people working with you.
If we did not enter any if, then we set the animation_frame to 0 to
reset the animation and call set_clip_to_set with the main data,
the animation number 0 (the "stay still animation") and an angle which
is not a multiple of 90 and so will not provoke a rotation change in
the set_clip_to_set sub procedure so we keep the current orientation.
The last thing, the wheel event response. We divide delta by five
to get a smaller impact of the wheel. Currently, it means: add 100%
of the original size for each 5 step of wheel. We use the scale
on both the X and Y axis so the whole character is scaled and it look
likes we got closer.
The whole program.