Tutorials
Articles
OpenGL Demos
Games
OpenGL Misc
MSG Board
About
Donate
Links
Home
Megabyte Softworks
C++, OpenGL, Algorithms




Current series: OpenGL 3.3
(Return to list of OpenGL 3.3 tutorials)

Download (1.74 MB)
7639 downloads. 54 comments
6.) Textures

Hello there and welcome to the 6th OpenGL 3.3 Tutorial. Here we are going one of the most used thing in 3D graphics - texture mapping (texturing).

What is texturing (for total newbies)

Texturing is a method for adding details to our scene by mapping texture images to our polygon. When we have a 3D model, and we want to render it with image mapped on it somehow, we feed OpenGL desired image (texture), texture coordinates (we're working with 2D textures now, so we will feed OpenGL with 2D texture coordinates), and then do some bureaucracy LULZ, like enabling texturing, and we are ready to go.

Texture mapping - how to do it

OK, first thing we need to do, is to be able to load pictures from disk and put them in some easy-to-use format, like RGB pixel per pixel. OpenGL doesn't deal with image loading, it just wants us to provide data in one such format, so that it can create a texture from it. And for purposes of loading images, I decided to go with FreeImage library, that is, as the name suggests, free, so no one will chase you after using it in your product LULZ. So go to:
http://freeimage.sourceforge.net/
and download it. After unpacking it somewhere to your libaries directory, add a new entry to Include Directories and Library Directories in your Visual Studio like this (it's explained in the first tutorial, in case you don't know where it is):

Now that we are able to load images, we can start working with textures. Textures in OpenGL are used similarly as other OpenGL objects - first we must tell OpenGL to generate textures, and then it provides us a texture name (ID), with which we can address the texture. To make things easy, we will create a wrapper C++ class that will encapsulate creation, deletion and every important thing related to texturing. Here is how the class looks like:


class CTexture
{
public:
   bool loadTexture2D(string a_sPath, bool bGenerateMipMaps = false);
   void bindTexture(int iTextureUnit = 0);

   void setFiltering(int a_tfMagnification, int a_tfMinification);

   int getMinificationFilter();
   int getMagnificationFilter();

   void releaseTexture();

   CTexture();
private:
   int iWidth, iHeight, iBPP; // Texture width, height, and bytes per pixel
   UINT uiTexture; // Texture name
   UINT uiSampler; // Sampler name
   bool bMipMapsGenerated;

   int tfMinification, tfMagnification;

   string sPath;
};

We will get directly into loadTexture function, which is the maybe the most important function in this tutorial:


bool CTexture::loadTexture2D(string a_sPath, bool bGenerateMipMaps)
{
   FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
   FIBITMAP* dib(0);

   fif = FreeImage_GetFileType(a_sPath.c_str(), 0); // Check the file signature and deduce its format

   if(fif == FIF_UNKNOWN) // If still unknown, try to guess the file format from the file extension
      fif = FreeImage_GetFIFFromFilename(a_sPath.c_str());

   if(fif == FIF_UNKNOWN) // If still unkown, return failure
      return false;

   if(FreeImage_FIFSupportsReading(fif)) // Check if the plugin has reading capabilities and load the file
      dib = FreeImage_Load(fif, a_sPath.c_str());
   if(!dib)
      return false;

   BYTE* bDataPointer = FreeImage_GetBits(dib); // Retrieve the image data

   iWidth = FreeImage_GetWidth(dib); // Get the image width and height
   iHeight = FreeImage_GetHeight(dib);
   iBPP = FreeImage_GetBPP(dib);

   // If somehow one of these failed (they shouldn't), return failure
   if(bDataPointer == NULL || iWidth == 0 || iHeight == 0)
      return false;

   // Generate an OpenGL texture ID for this texture
   glGenTextures(1, &uiTexture);
   glBindTexture(GL_TEXTURE_2D, uiTexture);

   int iFormat = iBPP == 24 ? GL_BGR : iBPP == 8 ? GL_LUMINANCE : 0;
   int iInternalFormat = iBPP == 24 ? GL_RGB : GL_DEPTH_COMPONENT; 

   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, iFormat, GL_UNSIGNED_BYTE, bDataPointer);

   if(bGenerateMipMaps)glGenerateMipmap(GL_TEXTURE_2D);

   FreeImage_Unload(dib);

   glGenSamplers(1, &uiSampler);

   sPath = a_sPath;
   bMipMapsGenerated = bGenerateMipMaps;

   return true// Success
}

First, when we provide an image file path to function, FreeImage will try to guess which file type it is (probably by extension, then by examining file headers maybe). We do this with functions FreeImage_GetFileType, FreeImage_GetFIFFromFilename, and FreeImage_FIFSupportsReading. This function will determine if the given file is image and if FreeImage is capable of reading it. Don't worry, it supports all major graphic formats, so it really shouldn't be a problem. If everything is good, we call FreeImage_Load to finally load the image to memory.

Very important thing about textures is, that their dimensions MUST be powers of 2. It is so for several reasons (well to be honest, I don't know exactly why it is so LULZ), but I can think of several reasons, that seems likely - like when creating mipmaps (more on that later), it may be problematic, or some memory alignments. If someone knows more on this stuff, you can write it to comments and I will edit the article. There are, however, extensions that allows arbitrary rectangular textures to be loaded, but in this tutorial, we will use 256x256 texture size.

Now we are ready to create an OpenGL texture from loaded data. First we must retrieve image properties, for later use in OpenGL. We store them in iWidth, iHeight, and iBPP member variables. We also retrieve data pointer to with FreeImage_GetBits function (the name may be little misleading). Then we finally generate texture by calling glGenTextures. It takes two parameters - how many textures we want, and where to store their names (classic convention). After creating texture object, we must bind it to tell OpenGL we are gonna work with this one, by calling glBindTexture. Its parameters are target, which can be GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, or some other parameters, like GL_TEXTURE_CUBE_MAP (we'll get onto this in later tutorials). Refer to the manual pages for list of all. In this tutorial, we will stick to 2D textures, so the target is GL_TEXTURE_2D. Second parameter is texture ID generated previously.

Now it seems we can finally upload texture data to GPU, but there is still one thing we must solve. FreeImage doesn't store our images in RGB format, on Windows, it's actually BGR, and this thing should be platform-dependant as far as I know. But this is no problem, when sending data to GPU, we'll just tell it that they're in BGR format. And now we really are ready to upload data to GPU... or we are? Yes, but a little word about texture filters should be said.

Texture filtering

When telling OpenGL texture data, we must also tell it, how to FILTER the texture. What does this mean? It's the way how OpenGL takes colors from image and draws them onto a polygon. Since we will probably never map texture pixel-perfect (the polygon's on-screen pixel size is the same as texture size), we need to tell OpenGL which texels (single pixels (or colors) from texture) to take. There are several texture filterings available. They are defined for both minification and magnification. What does this mean? Well, first imagine a wall, that we are looking straight at, and its screen pixel size is the same as our texture size (256x256), so that each pixel has a corresponding texel:

In this case, everything is OK, there is no problem. But, if we moved closer to the wall, then we need to MAGNIFY the texture - because there are now more pixels on screen than texels in texture, we must tell OpenGL how to fetch the values from texture. In this case, there are two filterings:

NEAREST FILTERING: GPU will simply take the texel, that is nearest to exactly calculated point. This one is very fast, as no additional calculations are performed, but it's quality is also very low, since multiple pixels have the same texels, and the visual artifacts are very bold. The closer to the wall you are, the more "squary" it looks (many squares with different colors, each square represents a texel).

BILINEAR FILTERING: This one doesn't only get the closest texel, but rather it calculates the distances from all 4 adjacent texels, and retrieves weighted average from them, depending on the distance. This results in a lot better quality than nearest filtering, but requires a little more computational time (on modern hardware, this time is negligible). Have a look at the pictures:

As you can see, bilinear filtering gives us smoother results. You may wonder, that I have also heard of trilinear filtering. Soon, we'll get into that as well..

The second case is, if we moved further from the wall. Now the texture is bigger than the screen render of our simple wall, and thus it must be MINIFIED. The problem is, that now multiple texels may correspond to single fragment. And what shall we do now? One solution may be to average all corresponding texels, but this may be really slow, as whole texture might potentionally fall into single pixel. The nice solution to this problem is called MIPMAPPING. The original texture is stored not only in its original size, but also downsampled to all smaller resolutions, with each coordinate divided by 2, creating a "pyramid" of textures (this image is from Wikipedia):

Particular images are called mipmaps. With mipmapping enabled, GPU selects a mipmap of appropriate size, according to the distance we see object from, and then perform some filtering. This results in higher memory consumption (exactly by 33%, as sum of 1/4, 1/16, 1/256... converges to 1/3), but gives nice visual results at very nice speed. And here is another filtering term - TRILINEAR filtering. What's that? Well, it's the almost same as bilinear filtering, but addition to it is that we take two nearest mipmaps, do the bilinear filtering on each of them, and then average results. The name TRIlinear is from the third dimension that comes into it - in case of bilinear we were finding fragments in two dimensions, trilinear filtering extends this to three dimensions.

Another, most computationally expensive, but with best results is ANISOTROPIC filtering. But this will be covered in some later tutorial, not this one, which should serve as introduction to texturing.

Finalizing our texture

After a brief explanation of texture filters, we can proceed with its creation. All we need to do is to send texture data to GPU, and then tell OpenGL in which format we stored them. Function for sending data to GPU is glTexImage2D. It's parameters (in order) are:

  1. target - in our case it is GL_TEXTURE_2D
  2. texture LOD - Level Of Detail - we set this to zero - this parameter is used for defining mipmaps. The base level (full resolution) is 0. All subsequent levels (1/4 of the texture size, 1/16 of the texture size...) are higher, i.e. 1, 2 and so on. But we don't have to do it manually (even though we can, and we don't even have to define ALL mipmap levels if we don't want to, OpenGL doesn't require that), there is luckily a function for mipmap generation (soon we'll get into that).
  3. internal format - specification says it's number of components per pixel, but it doesn't accept numbers, but constants like GL_RGB and so on (see spec). And even though we use BGR as format, we put here GL_RGB anyway, because this parameter doesn't accept GL_BGR, it really only informs about the number of components per texel. I don't find this very intuitive, but it's probably because of some backwards compatibility.
  4. width - Texture width
  5. height - Texture height
  6. border - width of border - in older OpenGL specifications you could create a border around texture (it's really useless), in new 3.3 specification (and also in future specifications, like 4.2 in time of writing this tutorial), this parameter MUST be zero
  7. format - Format in which we specify data, GL_BGR in this case
  8. type - data type of single value, we use unsigned bytes, and thus GL_UNSIGNED_BYTE as data type
  9. data - finally a pointer to the data

Phew, so many parameters. There's no need to remember them in order, if you need to use it, always consult specification. Important thing is that you understand what this function does. Now, the last thing that hasn't been covered, is creation of mipmaps. There are two ways - either we resize images ourselves, and then call glTexImage2D with different LODs, or we easily call function that OpenGL provides right after we uploaded data - glGenerateMipmaps. The only parameter is the target, which is GL_TEXTURE_2D in our case.

Now that we have data sent to GPU, we need to tell OpenGL how to filter the texture. Well, for those who remember OpenGL in older days (2.1 and below), we would do something like this to set filtering:


// Set magnification filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set minification filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

But not now. Now we are ready to move on. Problem of the above was, that if we wanted to use the same texture with different filterings, we could do it by constantly changing its parameters. Well it could be done somehow, but isn't there a nicer, more elegant way? Yes there is - and it's called samplers.

Samplers

I couldn't find a definition of sampler on them internets , but I will try to explain it as easy as possible. Sampling is the process of fetching a value from a texture at a given position, so sampler is an object where we store info of how to do it. Like which texture to use and all filtering parameters. If we want to change filtering, we just bind different samplers with different propertiees, and we're done. This line is copied from spec:

"If a sampler object is bound to a texture unit and that unit is used to sample from a texture, the parameters in the sampler are used to sample from the texture, rather than the equivalent parameters in the texture object bound to that unit."

One part of it basically says, that if a sampler is bound to the texture, its parameters supersedes texture parameters. So instead of setting texture parameters, we will create a sampler, which will do exactly this. Even though in this tutorial we create one sampler per one texture (so it's like without samplers), it's a more general solution and thus it's better. As all OpenGL objects, samplers are generated (we get their names), and then we access them with that name. So when loading texture, we just call glGenerateSamplers, and then we set its parameters with our member function:


void CTexture::setFiltering(int a_tfMagnification, int a_tfMinification)
{
   // Set magnification filter
   if(a_tfMagnification == TEXTURE_FILTER_MAG_NEAREST)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   else if(a_tfMagnification == TEXTURE_FILTER_MAG_BILINEAR)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   // Set minification filter
   if(a_tfMinification == TEXTURE_FILTER_MIN_NEAREST)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   else if(a_tfMinification == TEXTURE_FILTER_MIN_BILINEAR)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   else if(a_tfMinification == TEXTURE_FILTER_MIN_NEAREST_MIPMAP)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
   else if(a_tfMinification == TEXTURE_FILTER_MIN_BILINEAR_MIPMAP)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
   else if(a_tfMinification == TEXTURE_FILTER_MIN_TRILINEAR)
      glSamplerParameteri(uiSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

   tfMinification = a_tfMinification;
   tfMagnification = a_tfMagnification;
}

We just pass in values from enumerator structure, defined in texture.h, and we change the filtering parameters. In application, you can press F1 and F2 keys, to switch between minification and magnification filterings of ice texture (run application in windowed mode, because in window title bar you can see actual texture filters). You may notice, that in enumerator structure, there are only 5 minification filters, and if you google things you can find 6. I just didn't put there filtering, that takes closest two mipmaps, performs nearest criterion on them, and then averages results - it simply doesn't make much sense to do that (even though OpenGL allows that). But if you really want, you can try it (set minification filter to GL_NEAREST_MIPMAP_LINEAR).

I hope, that I have demystified texture filterings for you, and now, we are ready to see how texture mapping is done.

Texture Coordinates

Yeah, that's it. Finally we came into it. Texture coordinates (also called UV coordinates) are the way how to map texture along the polygon. We just need to provide appropriate texture coordinates with every vertex and we're done. In our 2D texture case, texture coordinate will be represented by two numbers, one along X axis (U coordinate), and one along Y Axis (V Coordinate):

So if we would like to map our texture to quad, we would simply provide (0.0, 1.0) coordinates to upper left vertex, (1.0, 1.0) to upper right vertex, (1.0, 0.0) to bottom-right vertex and (0.0, 0.0) to bottom-left vertex. But what if we wanted to map texture to let's say a triangle? Well, you probably may guess now, and this picture will demonstrate it:

We simply need to copy the shape of our polygon also in texture coordinates in order to map texture properly. If we exceed the <0..1> range, our texture gets mapped more times, let's say, if we mapped coordinates (0.0, 10.0), (10.0, 10.0), (10.0, 0.0) and (0.0, 0.0) to the quad, texture would be mapped 10 times on X Axis and 10 times on Y Axis. This texture repeating is default behavior, it can be turned off actually, so the texture cannot exceed these values, or if it does, only border values are taken (this is used when creating skyboxes for example).

Now that we know which texture coordinate values are right, we must learn how to provide them. Texture coordinate is just another vertex attribute. So when creating data for rendering in VBO, we add two additional floats per vertex for texture coordinates. Nothing else. We'll also need to add few lines into shaders as well. Starting from this tutorial, I will use my CVertexBuffer class, which wraps VBO and allows for dynamic addition of data (so I don't have to count number of polygons and size of VBO before rendering, I just add as many as I want, and then upload data to GPU). I'm just going to say it uses std::vector internally, and you can have a look at its code, if you're interested in it. We'll use one such for cube, pyramid and ground (which is only one quad, made of 2 triangles, textured with grass texture). Then we'll call glDrawArrays, but with different offsets, and different textures bound.

One important thing I changed in ths tutorial is the format of data. We don't have one VBO for vertices and one for texture coordinates, but with each vertex, we have three floats for vertex followed by two floats for texture coordinate. After that, we just need to tell OpenGL, when calling glVertexAttribPointer, what's the distance between two consecutive attributes (the STRIDE parameter). In this case, the distance between two consecutive vertex attributes is sizeof whole vertex data, i.e. sizeof(vec3)+sizeof(vec2) (it's 5 floats). You can find it in the initScene function. Don't forget to enable texturing, by calling glEnable(GL_TEXTURE_2D), it's in the end of initScene.

Accessing texture in fragment shader

This is the last thing that's covered in this extremely long tutorial LULZ is how to access texture data in fragment shader. The first thing we must do, is to pass texture coordinate, that is an input variable in vertex shader, further to fragment shader. The second important thing, is to create an uniform sampler2D variable in fragment shader. Here is how fragment shader looks like (vertex shader is almost the same as in previous tutorial, I recommend to have a look at it as well):


#version 330

in vec2 texCoord;
out vec4 outputColor;

uniform sampler2D gSampler;

void main()
{
   outputColor = texture2D(gSampler, texCoord);
}

With this variable, we will fetch texture data based on texture coordinates. From program, we just need to set sampler to one integer. What does this integer mean? It's the TEXTURE UNIT number. Texture unit is another term, that's important. You may have heard of multitexturing - mapping multiple textures at once. Well, one we can have multiple texture units, each of them can have a different texture bound, and then differentiate between them with their numbers. To specify which texture unit we use, we use function glActiveTexture. The number of texture units supported is graphic-card dependant, but this number should be sufficient for most uses (I'm too lazy to find out how many my GTX 260 has , but I guess it's 32 or 64). Since we never need to use more than one texture at once (we only need data from one texture in fragment shader), we will only use texture unit 0. In our rendering, we must first bind our texture to texture unit 0, and then we must set sampler uniform variable to 0 as well, to tell OpenGL, that with that uniform variable we want a texture, that's bound to texture unit 0. Then in fragment shader, we just call function texture2D, that takes sampler variable as first parameter, and texture coordinates as second parameter.

Short word in the end...

This is what has been done today (You can play around by rotating objects in arrow keys):
I hope that you don't have a headache after reading this tutorial. It may take some time for all those things to settle down in your head, but once they do, you will realize that it isn't that difficult at all. I would say, that people in AMD and nVidia have it difficult, to actually implement this OpenGL specification LULZ But that's not something we need to worry about. They are (probably) happy to do it LULZ, and we are users, that are happy to use it.

If you have any questions, you can write them to comments, or send me an e-mail. Next tutorial is going to be about blending, we'll make transparent objects, so stay tuned!



Download (1.74 MB)
7639 downloads. 54 comments
 
Name:

E-mail:
(Optional)
Entry:

Enter the text from image:



Smileys




RichardBum (ksis83182@first.baburn.com) on 03.10.2017 02:02:53
<a href=http://www.mundo-hoteles.es/030-nike-cortez-72-chile.html>Nike Cortez 72 Chile</a>
You shouldn't need to put up with crazy-crawly issues at your residence or visit a scattering of insects once you change an easy on in the evening do something to solve this problem now. Take advantage of the tips in the following paragraphs to get started on evicting these awful stuff from your own home. The longer you wait, the greater they procreate!In this article Is How To Get Greater Images Now!


The best way to decrease the consequences of getting older would be to exercising your system and also the mind. You will find exciting as well as simple ways to physical exercise your brain every day, many of these techniques include: crossword puzzles, term research puzzles, reading, products or any sort of hobby which will obstacle your brain. By training your mind you might be aiding the body keep its memory, which also know is essential as we get older.

GeraldThume (geraldNub@redirtraff.top) on 21.09.2017 19:12:35
web medical information
<a href="http://canadianpharmacyrxbsl.com/">canadian pharmacies shipping to usa</a>
canadian pharmacy online canada
<a href=http://canadianpharmacyrxbsl.com/?sertraline-zoloft>sertraline zoloft</a>
online canadian pharmacy
<a href="http://canadianpharmacyrxbsl.com/?viagra-ohne-rezept-aus-deutschland">viagra ohne rezept aus deutschland</a>
GreggBoade (zzhy65520@first.baburn.com) on 06.09.2017 16:17:20
junpndy

http://www.overdriverockband.co.uk/ray-ban-spectacles-for-women-745.htm
http://www.ras-net.co.uk/nike-free-run-flyknit-rainbow-767.htm
http://www.middlesbroughcyclecentre.co.uk/608-louis-vuitton-heels-fake.htm
http://www.tops4creditcards.co.uk/converse-glittery-750.htm
http://www.fuseboxdesign.co.uk/jordan-11-gamma-blue-262.php

<a href=http://www.corx.co.uk/nike-flyknit-racer-black-grey-469.php>Nike Flyknit Racer Black Grey</a>
<a href=http://www.middlesbroughcyclecentre.co.uk/139-dsquared-sneaker-new-runner.htm>Dsquared Sneaker New Runner</a>
<a href=http://www.middlesbroughcyclecentre.co.uk/335-philipp-plein-sneakers-blue.htm>Philipp Plein Sneakers Blue</a>
<a href=http://www.overdriverockband.co.uk/ray-ban-58014-fake-598.htm>Ray Ban 58014 Fake</a>
<a href=http://www.anime-ni.co.uk/vibram-five-fingers-komodo-sport-uk-548.php>Vibram Five Fingers Komodo Sport Uk</a>
Dennisbaipt (qhig55622@first.baburn.com) on 01.09.2017 10:20:28
<a href=http://www.hilal-media.de/519-longchamp-düsseldorf-telefon.php>Longchamp Düsseldorf Telefon</a>
Learn how to tie basic knots. From online guides to guides at the collection, there are a number of resources that can be used to instruct yourself this crucial skill. Use angling collection if you exercise to ensure that you can duplicate the outcome in the drinking water or shoreline.

<img>https://www.cityfloppers.de/images/newcitylv/3051-louis-vuitton-schuhe-berlin.jpg</img>

Do not transmit the spot of the budget. Be secretive about where you stand keeping your money and cherished information and facts. Being aware of exactly where it can be could give pickpockets a position. By no means placed your wallet inside your back bank account. When you are in a practice of doing this split it. Your back pocket is extremely easy to steal from.

<img>https://www.tachyonen-shop-davidwagner.de/images/tac2/9344-adidas-superstar-damen-schwarz.jpg</img>
GregoryNiz (fszc52665@first.baburn.com) on 18.08.2017 10:58:04
fcpsclp

http://www.trioelegiaque.fr/adidas-dragon-moins-cher-165.html
http://www.denishirst.fr/adidas-tubular-nova-primeknit-rouge-233.html
http://www.claudegouron.fr/louboutin-daim-bleu-381.php
http://www.denishirst.fr/adidas-nmd-femme-974.html
http://www.creer-jeu-concours.fr/665-air-jordan-10-on-feet.php

<a href=http://www.chokoloskee.fr/ralph-lauren-chaussure-465.php>Ralph Lauren Chaussure</a>
<a href=http://www.sebastienmagro.fr/adidas-tubular-invader-strap-camel-834.html>Adidas Tubular Invader Strap Camel</a>
<a href=http://www.dojodulac.fr/asics-gel-lyte-monkey-time-237.html>Asics Gel Lyte Monkey Time</a>
<a href=http://www.cheko.ch/nike-presto-grau>Nike Presto Grau</a>
<a href=http://www.wiime.fr/saucony-jazz-premium-683.html>Saucony Jazz Premium</a>
Richarddync (pzwc22339@first.baburn.com) on 03.08.2017 20:14:18
zsstzgd

http://www.sebastienmagro.fr/tubular-053.html
http://www.demandezleprogramme.fr/247-nike-air-force-lunar-black.html
http://www.procrea-stem-cells.ch/adidas-nmd-grise-841.cfm
http://www.fetish-unlimited.ch/lunettes-oakley-jawbreaker-392.php
http://www.pieces-center.fr/adidas-stan-smith-velour---femme-chaussures-268.php

<a href=http://www.betway-poker.fr/nike-magista-chaussure-967.php>Nike Magista Chaussure</a>
<a href=http://www.lyceerenedescartes77.fr/226-huarache-femme-run.html>Huarache Femme Run</a>
<a href=http://www.omake.fr/jordan-11-retro-low-noir-976.html>Jordan 11 Retro Low Noir</a>
<a href=http://www.fretsonfire.fr/406-presto-femme-rouge.html>Presto Femme Rouge</a>
<a href=http://www.essaisgratuits.fr/baskets-tods-972.php>Baskets Tod's</a>
Thomasgerm (kncb31537@first.baburn.com) on 19.07.2017 20:43:08
bstnqnh

http://www.fabulatia.it/061-oakley-9262.htm
http://www.montevarchicalcio.it/longchamp-nero-viaggio-borse-947.html
http://www.menteprofonda.it/prada-scarpe-autunno-inverno-2017-965.htm
http://www.ttwater.it/213-puma-limited-edition-2017.asp
http://www.starlightmusic.it/518-air-jordan-flight-nuove.php

<a href=http://www.nuovarca.it/nike-cortez-nere-938.asp>Nike Cortez Nere</a>
<a href=http://www.annagalante.it/040-hogan-scarpe-trovaprezzi.html>Hogan Scarpe Trovaprezzi</a>
<a href=http://www.polepositionmodellismo.it/new-era-pink-602.aspx>New Era Pink</a>
<a href=http://www.ezquote.it/485-adidas-originals-tubular-doom.asp>Adidas Originals Tubular Doom</a>
<a href=http://www.ubriacodamore.it/323-abercrombie-and-fitch-clothes-for-kids.html>Abercrombie And Fitch Clothes For Kids</a>
Thomasgerm (nctj39751@first.baburn.com) on 15.06.2017 20:07:52
adbkban

http://www.vivalur.fr/401-adidas-boost-shoes-list.php
http://www.restaurant-traiteur-creuse.fr/adidas-tubular-vs-y3-790.php
http://www.vivalur.fr/040-adidas-ultra-boost-multicolor-2.0.php
http://www.climat-concept.fr/adidas-eqt-modern-series-061.html
http://www.ChaussureAdidasonlineoutlet.fr/513-stan-smith-zebra-prix.htm

<a href=http://www.creagraphie.fr/840-adidas-zx-flux-junior-jd.html>Adidas Zx Flux Junior Jd</a>
<a href=http://www.vivalur.fr/254-adidas-boost-volley-review.php>Adidas Boost Volley Review</a>
<a href=http://www.estime-moi.fr/adidas-zx-flux-xeno-3m-190.php>Adidas Zx Flux Xeno 3m</a>
<a href=http://www.histoiresdinterieur.fr/adidas-ultra-boost-gold-medal-ebay-623.html>Adidas Ultra Boost Gold Medal Ebay</a>
<a href=http://www.beasys.fr/443-adidas-tubular-primeknit-sizing.htm>Adidas Tubular Primeknit Sizing</a>
Richarddync (ibjs83604@first.baburn.com) on 04.06.2017 00:33:16
xbgxwws

http://www.123gouter.fr/adidas-jeremy-scott-wings-2.0-pas-cher-071.php
http://www.aurelieadomicile.fr/511-puma-suede-noir-gum.php
http://www.dresden2020.de/069-nike-air-max-flyknit-1.php
http://www.aurelieadomicile.fr/360-basket-puma-femme-noir-et-or.php
http://www.christelle-barbin.fr/207-converse-blanc-cuir-homme.php

<a href=http://www.aurelieadomicile.fr/068-puma-chaussure-2017-noir.php>Puma Chaussure 2017 Noir</a>
<a href=http://www.extreme-hosting.co.uk/935-air-jordan-11.php>Air Jordan 11</a>
<a href=http://www.evil-e-low.de/457-nike-hyperadapt-preis.html>Nike Hyperadapt Preis</a>
<a href=http://www.fiestabrava.fr/converse-verte-basse-552.html>Converse Verte Basse</a>
<a href=http://www.extreme-hosting.co.uk/117-nike-air-max-90-black-and-white-suede.php>Nike Air Max 90 Black And White Suede</a>
Curtisst (cors33993@first.baburn.com) on 01.06.2017 05:56:16
jsyqfmd

http://www.sparkelecvideo.es/950-zapatillas-jordan-de-bebe-niña.html
http://www.maxicolor.nl/nike-free-run-5.0-dames-lichtblauw-731.html
http://www.berrynation.es/806-oakley-marshal-ferrari.html
http://www.spanish-realestate.es/648-adidas-futbol-sala-2015.asp
http://www.lexus-tiemens-arnhem.nl/808-clarks-amsterdam-sale.htm

<a href=http://www.newbalanceoutletfrance.fr/708-new-balance-cuir-rose.php>New Balance Cuir Rose</a>
<a href=http://www.cdaveghel.nl/asics-igs-530.htm>Asics Igs</a>
<a href=http://www.academievoorpsychiatrie.nl/092-adidas-gazelle-kaki.html>Adidas Kaki</a>
<a href=http://www.gugan.es/zapatos-louboutin-hombre-outlet-081.html>Zapatos Hombre</a>
<a href=http://www.adhi.es/nike-mercurial-vapor-viii-cr7-060.php>Nike Vapor</a>
Thomasgerm (hfhu81547@first.baburn.com) on 31.05.2017 09:21:42
ieivift

http://www.onegame.fr/new-balance-vert-homme-334.php
http://www.ileauxtresors.fr/chaussure-adidas-old-school-445.htm
http://www.lesfeesbouledeneige.fr/puma-suede-femme-noir-semelle-marron-817.html
http://www.graysands.co.uk/orange-nike-air-max-tavas-674.asp
http://www.la-baston.fr/chaussure-adidas-original-femme-571.html

<a href=http://www.izitea.fr/basket-new-balance-femme-running-898.html>Basket New Balance Femme Running</a>
<a href=http://www.imprimerieexpress.fr/puma-basket-militaire-731.php>Puma Basket Militaire</a>
<a href=http://www.la-baston.fr/adidas-femme-dentelle-prix-274.html>Adidas Femme Dentelle Prix</a>
<a href=http://www.los-granados-apartment.co.uk/517-adidas-nmd-r1-white.html>Adidas Nmd R1 White</a>
<a href=http://www.onegame.fr/new-balance-running-996-963.php>New Balance Running 996</a>
Jameslit (eirh7376@rng.marvsz.com) on 10.05.2017 23:19:52
abkyfej

http://www.vacu-step.fr/651-longchamp-rose.php
http://www.chiavaccifotografo.it/467-ralph-lauren-camicia-slim-fit.html
http://www.hotel-katerstuben.de/606-adidas-zx-flux-verve-lila.htm
http://www.triathlon-bous.de/adidas-originals-nmd-runner-669.php
http://www.support4marketing.de/nike-flyknit-racer-rainbow-992.html

<a href=http://www.forumados.fr/239-acheter-en-ligne-chez-hollister.php>Acheter En Ligne Chez Hollister</a>
<a href=http://www.ordineavvocaticasale.it/186-giacca-hollister-uomo.html>Giacca Hollister Uomo</a>
<a href=http://www.comferenza.it/camicia-ralph-lauren-bimbo-557.php>Camicia Ralph Lauren Bimbo</a>
<a href=http://www.santopadreracingteam.it/681-oakley-snowboard.php>Oakley Snowboard</a>
<a href=http://www.santopadreracingteam.it/850-oakley-occhiali-da-sole-ebay.php>Oakley Occhiali Da Sole Ebay</a>
Curtisst (mvms45324@rng.marvsz.com) on 09.05.2017 04:58:01
yaymlco

http://www.onegame.fr/new-balance-femme-noir-et-doré-322.php
http://www.los-granados-apartment.co.uk/068-adidas-shoes-for-women-2014-casual.html
http://www.los-granados-apartment.co.uk/963-adidas-neo-2015-shoes.html
http://www.izitea.fr/new-balance-574-kaki-853.html
http://www.lesfeesbouledeneige.fr/puma-suede-beige-rihanna-241.html

<a href=http://www.graysands.co.uk/nike-air-force-1-brown-207.asp>Nike Air Force 1 Brown</a>
<a href=http://www.kaptur.fr/466-puma-creepers-velvet-rose.html>Puma Creepers Velvet Rose</a>
<a href=http://www.la-baston.fr/tubular-runner-junior-311.html>Tubular Runner Junior</a>
<a href=http://www.lesfeesbouledeneige.fr/puma-rihanna-style-833.html>Puma Rihanna Style</a>
<a href=http://www.lesfeesbouledeneige.fr/puma-homme-2017-146.html>Puma Homme 2017</a>
Richarddync (fizp72667@rng.marvsz.com) on 04.05.2017 16:01:57
fifywdf

http://www.dresden2020.de/682-nike-free-run-2-damen-schwarz-weiß.php
http://www.evil-e-low.de/035-nike-hypershift-grau.html
http://www.campingcarsonway.fr/658-adidas-originals-tubular-radial.html
http://www.campingcarsonway.fr/023-ultra-boost-sns.html
http://www.assurance-csp.fr/asics-30-euros-300.htm

<a href=http://www.dresden2020.de/340-roshe.php>Roshe</a>
<a href=http://www.campingcarsonway.fr/482-zx-flux-noir-et-rose-fleur.html>Zx Flux Noir Et Rose Fleur</a>
<a href=http://www.campingcarsonway.fr/088-yeezy-boost-350-pirate-black-2016.html>Yeezy Boost 350 Pirate Black 2016</a>
<a href=http://www.123gouter.fr/adidas-nmd-femme-bordeaux-193.php>Adidas Nmd Femme Bordeaux</a>
<a href=http://www.extreme-hosting.co.uk/972-nike-gray-shoes-women.php>Nike Gray Shoes Women</a>
MerlinBot (iiqm66283@rng.marvsz.com) on 18.04.2017 18:11:51
<a href=https://www.kristiinakoskentola.nl/images/kristiinakoskentola/3342-nike-cortez-roze.jpg>Nike Cortez Roze</a>
Tend not to ignore the necessity of relaxation in muscle development. Believe it or not, development really takes place during rest, if you are not acquiring enough of it, your muscled is not going to expand or be effectively conditioned. Training encourages muscles, and throughout rest the body gets to just work at constructing the muscles. You need to realize this procedure and aspect sleep in your muscle mass conditioning or creating schedule.

þÿ

If you're each student seeking to increase your memory space to get a examination, the most detrimental action you can take is cram. Seeking to learn a great deal in not enough time will not likely allow you to maintain nearly anything whatsoever. You will simply knowledge bits of pieces of the material and can not be able to properly discover what you must.
<a href=https://www.herz-jesu-huellen.de/images/img-herz/3258-nike-flyknit-roshe-run-grey.jpg>Nike Flyknit Roshe Run Grey</a>

þÿ
Curtisst (bvtk92896@catch@rng.marvsz.com) on 14.04.2017 08:40:34
gxjqrga

http://www.los-granados-apartment.co.uk/188-adidas-basketball-shoes-low-2017.html
http://www.graysands.co.uk/nike-air-huarache-light-safari-womens-139.asp
http://www.los-granados-apartment.co.uk/397-adidas-energy-boost-red.html
http://www.ileauxtresors.fr/adidas-ultra-boost-triple-white-2.0-284.htm
http://www.imprimerieexpress.fr/puma-suede-platform-core-beige-394.php

<a href=http://www.onegame.fr/new-balance-rouge-bordeaux-femme-773.php>New Balance Rouge Bordeaux Femme</a>
<a href=http://www.consumabulbs.co.uk/808-puma-ignite-limitless-hi-tech-extreme.html>Puma Ignite Limitless Hi Tech Extreme</a>
<a href=http://www.consumabulbs.co.uk/012-puma-ignite-xt-graphic.html>Puma Ignite Xt Graphic</a>
<a href=http://www.onegame.fr/new-balance-574-beige-rose-916.php>New Balance 574 Beige Rose</a>
<a href=http://www.los-granados-apartment.co.uk/083-adidas-zx-flux-adv-virtue-primeknit.html>Adidas Zx Flux Adv Virtue Primeknit</a>
Richarddync (tepj57110@rng.marvsz.com) on 05.04.2017 22:55:00
icocucb

http://www.trapani1.it/659-scarpe-louboutin-online.html
http://www.skunky.it/306-hogan-baby.php
http://www.stonefree.it/765-prada-shoes.htm
http://www.villaprati.it/adidas-ace-16.3-primemesh-529.htm
http://www.veneto-arte.it/salomon-xa-pro-3d-ultra-2-gtx-opinioni-386.php

<a href=http://www.taxline.it/scarpe-da-calcio-di-belotti-516.htm>Scarpe Da Calcio Di Belotti</a>
<a href=http://www.trapani1.it/152-pigalle-louboutin.html>Pigalle Louboutin</a>
<a href=http://www.villarianna.it/scarpe-tacco-tronchetto-580.asp>Scarpe Tacco Tronchetto</a>
<a href=http://www.veneto-arte.it/scarpe-salomon-uomo-796.php>Scarpe Salomon Uomo</a>
<a href=http://www.villaprati.it/adidas-calcio-nere-rosse-786.htm>Adidas Calcio Nere Rosse</a>
Richarddync (yquf1255@rng.marvsz.com) on 30.03.2017 16:51:16
ogeztfw

http://www.topgames365.fr/air-max-thea-rouge-et-noir-538
http://www.salon-julienkoch.fr/527-reebok-classic-nylon-femme-noir.html
http://www.salon-julienkoch.fr/197-reebok-blanche-femme.html
http://www.topgames365.fr/nike-air-max-thea-rose-549
http://www.artestyle.it/?a=30

<a href=http://www.saveursdelapelterie.fr/nike-chaussure-2015-236.htm>Nike Chaussure 2015</a>
<a href=http://www.airmaxwomenshop.co.uk/nike-air-max-women-2015-grey>Nike Air Max Women 2015 Grey</a>
<a href=http://www.salon-julienkoch.fr/420-chaussure-reebok-blanche.html>Chaussure Reebok Blanche</a>
<a href=http://www.toys4us.fr/nike-air-max-thea-rouge-framboise-796.html>Nike Air Max Thea Rouge Framboise</a>
<a href=http://www.topgames365.fr/air-max-thea-militaire-742>Air Max Thea Militaire</a>
Curtisst (lbtq87749@rng.marvsz.com) on 30.03.2017 06:48:31
sorqmkm

http://www.barreau-de-saint-pierre.fr/250-salomon-ellipse-2-aero.php
http://www.lessoinsdemariemassageenergetique.fr/538-chaussure-ralph-lauren-femme-pas-cher.php
http://www.miolands-mode-video.fr/945-prix-chaussure-mbt-homme.php
http://www.minitrain.fr/675-fila-original-fitness-rouge.htm
http://www.lessoinsdemariemassageenergetique.fr/322-basket-hugo-boss-ebay.php

<a href=http://www.thierryobadia.fr/998-palladium-homme-grise.html>Palladium Homme Grise</a>
<a href=http://www.miolands-mode-video.fr/032-supra-shoes-france.php>Supra Shoes France</a>
<a href=http://www.lesagapes-nantes.fr/hogan-olympia-homme-2017-277.php>Hogan Olympia Homme 2017</a>
<a href=http://www.messengercity.fr/079-mizuno-wave-rider-18-osaka.php>Mizuno Wave Rider 18 Osaka</a>
<a href=http://www.dany-multi-services.fr/248-chaussure-boxe-under-armour.php>Chaussure Boxe Under Armour</a>
Thomasgerm (blaj78498@catch@rng.marvsz.com) on 28.03.2017 01:12:53
ecfamlt

http://www.berwynmountainpress.co.uk/adidas-tubular-nova-225.html
http://www.zonnigemuziek.nl/386-hyperdunk-nike-zoom.htm
http://www.sjoraddningsbatar.se/583-vans-skor-karlstad.php
http://www.tarvisioscacchi.it/596-adidas-gazelle-nere-suola-marrone.html
http://www.itcigarrilloelectronico.es/748-adidas-primeknit-16.1.html

<a href=http://www.c-p-c.fr/833-adidas-neo-label-ortholite-2017.htm>Adidas Neo Label Ortholite 2017</a>
<a href=http://www.aletourist.nu/970-puma-roma-ayakkabı-erkek.htm>Puma Roma Ayakkabı Erkek</a>
<a href=http://www.itcigarrilloelectronico.es/166-zapatillas-adidas-pure-boost-zg-trainer.html>Zapatillas Adidas Pure Boost Zg Trainer</a>
<a href=http://www.freiberufler-netzwerk.de/819-adidas-originals-schuhe-damen-rot.php>Adidas Originals Schuhe Damen Rot</a>
<a href=http://www.fiashosting.se/reebok-crossfit-nano-5.0-vs-6.0-378.php>Reebok Crossfit Nano 5.0 Vs 6.0</a>
Jump to page:
1 2 3