computer graphics 3 lecture 3 opengl
Download
Skip this Video
Download Presentation
Computer Graphics 3 Lecture 3: OpenGL

Loading in 2 Seconds...

play fullscreen
1 / 60

Computer Graphics 3 Lecture 3: OpenGL - PowerPoint PPT Presentation


  • 124 Views
  • Uploaded on

Computer Graphics 3 Lecture 3: OpenGL. Pr. Min Chen Dr. Benjamin Mora. University of Wales Swansea. 1. Benjamin Mora. Content. Introduction to OpenGL-NVidia Dawn Demo. Different “drawable” primitives in OpenGL. OpenGL Pipeline and Matrix Transformations. Lighting. Textures.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Computer Graphics 3 Lecture 3: OpenGL' - abel-casey


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
computer graphics 3 lecture 3 opengl

Computer Graphics 3Lecture 3:OpenGL

Pr. Min Chen

Dr. Benjamin Mora

University of Wales Swansea

1

Benjamin Mora

content
Content
  • Introduction to OpenGL-NVidia Dawn Demo.
  • Different “drawable” primitives in OpenGL.
  • OpenGL Pipeline and Matrix Transformations.
  • Lighting.
  • Textures.
  • Initialization of the OpenGL machine and OpenGL coding.
  • Advanced Features.

University of Wales Swansea

2

Benjamin Mora

dawn demo
Dawn Demo

University of Wales Swansea

3

Benjamin Mora

introduction
Introduction

University of Wales Swansea

4

Benjamin Mora

what is opengl
What Is OpenGL?
  • OpenGL is a C (Graphics) Library allowing rendering (i.e., displaying) 3D objects like triangles.
  • Conceived in such a way that most routines are hardware accelerated.
  • Similar to Direct3D (DirectX, Microsoft) on many points.
  • OpenGL 1.0 has been introduced in 1992 by SGI (Silicon Graphics Incorporation).
  • Current Version 3.0.
  • Available now on every PC equipped with a descent graphics card (NVidia, ATI, also Intel…).

University of Wales Swansea

5

Benjamin Mora

what is opengl1
What Is OpenGL?
  • Pros:
    • Industry Standard (not only used in games)
    • Hardware-accelerated.
      • Specially designed GPUs.
      • Software-based versions are by far slower.
    • Portable (Linux, Windows, Macintosh, etc…).
    • Lot of documentation.
      • www.opengl.org
      • The OpenGL Programming Guide 4th Edition The Official Guide to Learning OpenGL Version 1.4.
      • OpenGL forums.
    • Still evolving: more and more options for more realistic renderings.

University of Wales Swansea

6

Benjamin Mora

what is opengl2
What Is OpenGL?
  • Cons:
    • State Machine: Awful programming, difficult to debug, and difficult for beginners!!!
      • Supposed to get better with the 3.0 release
    • Computer Graphics concepts must be learned.
    • Brute force approach: Hardware-Accelerated, but not optimized.
    • Not very flexible: Some computer graphics algorithms cannot take advantage of OpenGL.
    • Not the only way to display objects: Processing a huge amount of data can be faster in software under some conditions.

University of Wales Swansea

7

Benjamin Mora

what is opengl3
What Is OpenGL?
  • OpenGL does not contain a window manager, so an OpenGL rendering context (i.e., an OpenGL windows) must be created through another library (MFCs (?), GLUT, FLTK, GTK…).
  • To use OpenGL, the code should include the correct libraries and files:
    • #include <gl/gl.h>
    • OpenGL extensions must be included separately.
  • OpenGL is mainly used in a C/C++ context, but extensions of the API to other languages exist (OpenGL for java, delphi,…).

University of Wales Swansea

8

Benjamin Mora

how opengl works
How OpenGL works?
  • Aim: Rendering (i.e. displaying) a 3D scene.
  • Objects are “rendered” (drawn) into an invisible frame-buffer (image).
  • When all the objects have been processed, the frame-buffer becomes the new image appearing in your window (double buffering).
    • Ideally 30 fps or more.

University of Wales Swansea

9

Benjamin Mora

how opengl works1
How OpenGL works?
  • Rendering an image needs two main steps.
    • Setting up the parameters.
      • Telling OpenGL where the camera (viewpoint) is located.
      • Telling OpenGL about the lights.
        • position of the lights.
        • Type of lighting, colors.
      • Many other parameters according to the needs.
    • Telling the system where the primitives (basic forms like triangles that represent the object) are located in space.
      • Previous parameters will be taken into account for rendering.
      • If the object is opaque, primitives can be drawn in any order.
      • Every time a primitive is declared, OpenGL rasterizes (drawn) it on the frame-buffer, and keeps only its visible parts using the z-buffer test.

University of Wales Swansea

10

Benjamin Mora

how opengl works2

Projection

Camera System

Primitive

How OpenGL works?
  • The vertices send to the OpenGL machine follow a projection pipeline, before performing an on-screen rasterization (area filling) using a scan-line algorithm.

University of Wales Swansea

11

Benjamin Mora

how opengl works3

Initial Frame-Buffer

After the second primitive rasterization

After the first primitive rasterization

How OpenGL works?
  • Example:
  • Primitives enter the graphics pipeline when specifying their vertex (points) location.

University of Wales Swansea

12

Benjamin Mora

different drawable primitives in opengl
Different “drawable” primitives in OpenGL

University of Wales Swansea

13

Benjamin Mora

opengl primitives
OpenGL primitives

5

5

4

4

1

1

3

3

2

2

GL_POINTS

GL_LINES

GL_LINE_STRIP

GL_LINE_LOOP

GL_POLYGON

1

1

1

2

1

2

3

2

3

2

3

1

2

3

4

4

4

4

4

5

5

5

3

5

6

6

GL_TRIANGLE_STRIP

GL_TRIANGLES

GL_TRIANGLE_FAN

GL_QUADS

GL_QUAD_STRIP

University of Wales Swansea

14

Benjamin Mora

sending primitives to opengl
Sending primitives to OpenGL
  • A primitive mode must be setup first (e.g., glBegin(GL_TRIANGLES)).
  • Vertex coordinates must then be send to the pipeline
    • glVertex function, see later for code!
  • GL_TRIANGLES case
    • Every time 3 consecutive vertices have been sent to the pipeline, a new triangle rasterization occurs.

University of Wales Swansea

15

Benjamin Mora

primitive rasterization
Primitive Rasterization
  • Every pixel on the projection is called a “fragment”.
  • For every fragment, many parameters like the colors and transparency (RGBA), depth, and the texture coordinates are linearly interpolated.

Rasterization

Linear Interpolation

University of Wales Swansea

16

Benjamin Mora

primitive rasterization1
Primitive Rasterization
  • Different types (precisions) of colors can be used with OpenGL: [Black Value..White Value]
    • GL_UNSIGNED_BYTE: [0..255].
    • GL_UNSIGNED_SHORT: [0..65535].
    • GL_FLOAT: [0..1.0].
  • Usually, colors are clamped to [0..1].

University of Wales Swansea

17

Benjamin Mora

opengl pipeline and matrix transformations
OpenGL Pipeline and Matrix Transformations

University of Wales Swansea

18

Benjamin Mora

regular opengl pipeline
(Regular) OpenGL Pipeline
  • 4D vertex coordinates are expressed in the camera coordinate system by applying a sequence of (4D) transformations.
    • Pipeline and matrices fixed before processing a flow of vertices.

Eye/Camera coordinates

World coordinates

Modelview Matrix

Projection Matrix

Normalized device coordinates

Clip coordinates

Viewport Transformation

Perspective Division

Window Coordinates

University of Wales Swansea

19

Benjamin Mora

opengl pipeline

Object as stored in memory

OpenGL Pipeline

z

World coordinate system

x

o

University of Wales Swansea

20

Benjamin Mora

opengl pipeline1
OpenGL Pipeline

z

x

o

1-Modelview transform: Moving objects in space

2-Projection transform: Take into consideration the camera. Coordinates are now expressed in the camera coordinate system

3-w division followed by the viewport transform then occur to find the vertex projections. Once this done for a sufficient number vertices (e.g., 3 for a triangle), object rasterization can happen

University of Wales Swansea

21

Benjamin Mora

opengl pipeline2
OpenGL Pipeline
  • OpenGL is a state machine.
    • The matrices must be set before sending the graphic primitives (e.g. triangles) into the pipeline.
    • 2 main matrix stacks actually:
      • GL_MODELVIEW
        • Used to specify the camera position and/or the model position.
      • GL_PROJECTION
        • Used in order to specify the projection type, and clip coordinates.
  • Before applying transformations, the relevant stack must be specified:
    • Setting up the current matrix to modelview:
      • glMatrixMode(GL_MODELVIEW);
    • Use glLoadIdentity() to reset it.

University of Wales Swansea

22

Benjamin Mora

opengl pipeline3
OpenGL Pipeline
  • The current matrix is the matrix in top of the stack.
    • void glPushMatrix();
      • Make a copy of the matrix in top of the stack and put it on the top.
    • void glPopMatrix();
      • Remove the top matrix from the stack.
  • Loading the identity matrix.
    • glLoadIdentity();
    • Required before doing any rotation translation.
  • Stacks are used because they are useful to specify relative coordinate systems.

University of Wales Swansea

23

Benjamin Mora

opengl pipeline modelview matrix
OpenGL Pipeline: Modelview matrix
  • The modelview matrix can be used to both set the camera location and to move objects in space.
  • The projection matrix should be used to specify either the orthographic projection or the perspective projection
    • Use of either glOrtho or glFrustum to specify them
    • Used for normalizing coordinates between -1 and 1.
      • Required for the quantization of the z value

Rotation matrix created from an angle and a line in the direction x,y,z that cross the origin

Translation Matrix

University of Wales Swansea

24

Benjamin Mora

projection matrix glortho
Projection Matrix: glOrtho
  • Need to specify a 6-face box with 6 parameters.
  • Normalized coordinates between -1 and 1 after this stage.
  • void glOrtho(glDouble left, glDouble right, glDouble. bottom,glDouble top, glDouble near, glDouble far);

University of Wales Swansea

25

Benjamin Mora

projection matrix glfrustum
Projection Matrix: glFrustum
  • void glFrustum(glDouble left, glDouble right, glDouble bottom,glDouble top, glDouble near, glDouble far);
  • Non Linearity:

University of Wales Swansea

26

Benjamin Mora

perspective division
Perspective Division
  • Once the vertices have been transformed, we need to know their projection into the image space.
  • Image coordinates are still expressed as [-1, 1]

Projection on x [-1..1]

Fragment Depth

University of Wales Swansea

27

Benjamin Mora

viewport
Viewport
  • Map the normalized x and y coordinates to a portion of the image.
  • void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);

x+width,y+height

image

x,y

0,0

University of Wales Swansea

28

Benjamin Mora

viewport1
Viewport
  • Map the normalized x and y coordinates to a portion of the image.
  • void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);

x+width,y+height

image

x,y

0,0

University of Wales Swansea

29

Benjamin Mora

z buffer test
Z-Buffer test
  • Example:

Final image

Final z-buffer

University of Wales Swansea

30

Benjamin Mora

z buffer test1
Z-Buffer test
  • Once the vertices projected, rasterization occurs.
  • Primitives can be sent to the graphics hardware in any order, thanks to the z-buffer test that will keep the nearest fragments.
  • A z value is stored for every pixel (z-buffer).
  • Algorithm:

If the rasterized z-value is less than the current z-value

Then replace the previous color and z-value by the new ones

University of Wales Swansea

31

Benjamin Mora

stencil test
Stencil test
  • A stencil buffer can be used for implementing complex algorithms (e.g., Shadow volumes).
  • A value is associated with every pixel.
  • The stencil test is performed after the z-test and compare the current stencil value with a reference value.
  • The stencil value can possibly be incremented every time a fragment passes the stencil test.

University of Wales Swansea

32

Benjamin Mora

stencil test1
Stencil test

http://www.opengl.org/resources/tutorials/advanced/advanced97/notes/node196.html

University of Wales Swansea

33

Benjamin Mora

lighting
Lighting.

University of Wales Swansea

34

Benjamin Mora

opengl lighting model
OpenGL Lighting Model
  • In real life, every material has its own reflection properties (called BRDF, i.e. Bidirectional Reflectance Distribution Function).
  • Illumination is computed from the light source position, the surface orientation and the camera position.
  • Illumination is computed at

the vertices, and then interpolated

for every fragment.

University of Wales Swansea

35

Benjamin Mora

opengl lighting model phong
OpenGL Lighting Model (Phong)
  • 3 components:
    • Ambiant.
      • Do not depend of the light

source.

    • Diffuse.
      • The light is evenly reflected

in all direction.

    • Specular.
      • The reflection is predominant in a given direction.
      • The specular coefficient can be varied.
  • The light intensity can decrease according the distance (constant, linear or quadratic).

University of Wales Swansea

36

Benjamin Mora

opengl lighting model1
OpenGL Lighting Model

http://en.wikipedia.org/wiki/Phong_shading

University of Wales Swansea

37

Benjamin Mora

opengl lighting model2
OpenGL Lighting Model
  • OpenGL formula:
  • A “light” can be created, specifying all the required constants for the light.
  • A “material” can be created in OpenGL, specifying all the constants for the surface.

University of Wales Swansea

38

Benjamin Mora

model limitations
Model Limitations
  • No native shadows.
    • Shadows can be implemented by using specific algorithms and texture mapping.
  • Phong shading is just an imperfect model.
    • Global (i.e. realistic) illumination can not be done efficiently.
  • Better to interpolate normals first, and then compute shading.
  • Faked Normals.
    • The actual surface derivative do not usually match the specified normal.

University of Wales Swansea

39

Benjamin Mora

texture mapping
Texture Mapping
  • OpenGL interpolates the texture coordinates for every rasterized fragment and then fetches the pixel from the texture.
  • Textures are stored on the graphics board and are highly optimized.
    • Textures must be loaded first.
    • Texture coordinates must be attributed to vertices at the same time as vertex normals and vertex coordinates.
      • See next slides.

University of Wales Swansea

40

Benjamin Mora

initialization of the opengl machine and opengl coding
Initialization of the OpenGL Machine and OpenGL Coding.

University of Wales Swansea

41

Benjamin Mora

opengl coding
OpenGL Coding
  • First, set the parameters.
    • Viewpoint (camera).
    • Lights.
    • Materials.
    • Textures.
    • Etc…
  • Second, tell OpenGL the primitives to render, possibly specifying for every vertex its:
    • Colors.
    • Normals.
    • Texture Coordinates.

University of Wales Swansea

42

Benjamin Mora

opengl coding1
OpenGL Coding
  • #include <gl/gl.h>
  • Enabling some specific features:
    • void glEnable(GLenum cap);
    • void glDisable(GLenum cap);
    • glEnable(GL_DEPTH_TEST);//Enabling z-buffer
    • glEnable(GL_LIGHTING);//Enabling lighting.
    • glEnable(GL_LIGHT0);//Enabling light 0 (at least 8 lights)
    • glEnable(GL_TEXTURE_2D);//Enabling 2D textures

University of Wales Swansea

43

Benjamin Mora

opengl coding2
OpenGL Coding
  • Specifying the current matrix:
    • void glMatrixMode (GLenum mode);
      • glMatrixMode(GL_MODELVIEW);
      • glMatrixMode(GL_PROJECTION);
  • Initializing the current matrix:
    • void glLoadIdentity();
  • Handling the matrix stack:
    • void glPushMatrix ( );//New copy on the top of the stack.
    • void glPopMatrix ( ); //Remove the top of the stack.

University of Wales Swansea

44

Benjamin Mora

opengl coding3
OpenGL Coding
  • Rotations (modifying the current matrix):
    • void glRotated ( GLdouble angle , GLdouble x , GLdouble y , GLdouble z );
    • void glRotatef ( GLfloat angle , GLfloat x , GLfloat y , GLfloat z );
  • Translations (modifying the current matrix):
    • void glTranslated ( GLdouble x, GLdouble y, GLdouble z );
    • void glTranslatef ( GLfloat x , GLfloat y , GLfloat z );
  • Scaling (modifying the current matrix):
    • void glScaled ( GLdouble x , GLdouble y , GLdouble z );
    • void glScalef ( GLfloat x , GLfloat y , GLfloat z );

University of Wales Swansea

45

Benjamin Mora

opengl coding4
OpenGL Coding
  • Erasing the Frame-Buffer:
    • void glClearColor ( GLclampf red , GLclampf green , GLclampf blue , GLclampf alpha ); //Defines a clear color
    • void glClear ( GLbitfield mask ); //Clear the image
  • Examples:
    • glClear(GL_COLOR_BUFFER_BIT |

GL_DEPTH_BUFFER_BIT |

GL_ACCUM_BUFFER_BIT |

GL_STENCIL_BUFFER_BIT );

University of Wales Swansea

46

Benjamin Mora

opengl coding5
OpenGL Coding
  • Sending graphics primitives to the OpenGL machine:

glBegin(GL_LINES); //Specify lines. Could be GL_TRIANGLES, etc…

//First vertex

glColor3f(1.0,0.,0.);//3 float colors for the first vertex

glNormal3f(0.707,0.707,0); //first normal

glTexcoord2f(0,0); //First texture coordinate

glVertex3f(500,100,2); //first vertex

//Second vertex

glColor4f(1.0,0.,0.,1.);//4 float colors (last value: opacity)

glNormal3fv(v); //gives a vector of float as parameters

glTexcoord2f(1,1); //Second texture coordinate

glVertex3d(500,100,2);//double instead of float

glEnd(); // End of the vertex flow

University of Wales Swansea

47

Benjamin Mora

opengl coding6
OpenGL Coding
  • Initializing lighting

void GLRenderer::InitLighting()

{

float ambiant[4]= {0.2,0.2,0.2,1.};

float diffuse[4]= {0.7,0.7,0.7,1.};

float specular[4]= {1,1,1,1.};

float exponent=8;

// glMatrixMode(GL_MODELVIEW);

// glLoadIdentity();

// Be careful here: the lights go through the OpenGL transform pipeline

float lightDir[4] = {0,0,1,0};

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glLightfv(GL_LIGHT0,GL_AMBIENT,ambiant);

glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);

glLightfv(GL_LIGHT0,GL_SPECULAR,specular);

glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,exponent);

glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDir);

}

University of Wales Swansea

48

Benjamin Mora

opengl coding7
OpenGL Coding
  • Initializing texturing

unsigned int *textureId=new unsigned int[nbOfTextures];

glGenTextures(nbOfTextures,textureId);

for (i=0;i<nbOfTextures;i++)

{

glBindTexture(GL_TEXTURE_2D, textureId[i]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, textureDimensionsX[i], textureDimensionsY[i], 0,GL_RGB,GL_UNSIGNED_BYTE, texture[i]);

}

University of Wales Swansea

49

Benjamin Mora

advanced features
Advanced Features.

University of Wales Swansea

50

Benjamin Mora

advanced features1
Advanced Features
  • Limitations:
    • OpenGL 1.1 was limited to the Phong shading model.
    • Pixel precision may depend on the graphics card manufacturer (usually 8 bits per color).
    • Creating real-time shadows and more complex effects is difficult.
    • Power-of-two textures.
    • Fixed rendering pipeline.
    • Only one possible rendering per frame.
  • Main manufacturers: ATI, NVidia, SGI, XGI.
  • Functionalities and extensions may differ from the different manufacturers => Specific code must often be developed for each platform.

University of Wales Swansea

51

Benjamin Mora

advanced features vertex arrays
Advanced Features: Vertex Arrays
  • On modern PC platforms, the video card communicate with the CPU through a “slow” AGP or PCI-express bus.
  • Too much communication can kill performance.
    • e.g., processing a lot of small triangles.
  • The fast video memory associated with the GPU can be used to store the vertices and reduce the communication bandwidth.

University of Wales Swansea

52

Benjamin Mora

advanced features vertex arrays1
Advanced Features: Vertex Arrays
  • Up to six arrays can be specified:

void VertexPointer ( int size, enum type, sizei stride, void *pointer ) ;

void ColorPointer ( int size, enum type, sizei stride, void *pointer ) ;

void TexCoordPointer ( int size, enum type, sizei stride, void *pointer ) ;

void IndexPointer ( enum type, sizei stride, void *pointer ) ;

void NormalPointer ( enum type, sizei stride, void *pointer ) ;

void EdgeFlagPointer ( sizei stride, void *pointer ) ;

www.opengl.org

University of Wales Swansea

53

Benjamin Mora

advanced features vertex arrays2
Advanced Features: Vertex Arrays
  • Other functions are required to make it work.

void EnableClientState ( enum array ) ;

void DisableClientState ( enum array ) ; void ArrayElement ( int i ) ; void DrawArrays ( enum mode, int first, sizei count ) ;

void DrawElements ( enum mode, sizei count, enum type, void *indices ) ;

University of Wales Swansea

54

Benjamin Mora

advanced features extensions
Advanced Features: Extensions
  • Since OpenGL 1.2, extensions are supported.
  • Main Extensions:
    • Floating-point extensions to get a better precision at the frame buffer level.
      • ATI: 24 bit precision (now 32). NVidia: 16 or 32 bit precision.
      • High Dynamic Range (HDR) images, Tone Mapping.
    • Non-Power-of-Two textures: Saves memory.
    • Render-to-Texture (Cube Maps).
      • Shadow Maps.
    • Bump-Mapping.
    • Vertex and Fragment programs.
      • Floating-point precision at the program level.

University of Wales Swansea

55

Benjamin Mora

advanced features extensions1
Advanced Features: Extensions

char* extensionsList = (char*) glGetString(GL_EXTENSIONS);

// All the supported extensions are inside the string

// extensionsList.

//Example for getting the 3D texture functionality.

//First step: Declare a function type

typedef void (APIENTRY * PFNGLTEXIMAGE3DPROC)

(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)

PFNGLTEXIMAGE3DPROC glTexImage3D; // Declare a function pointer

glTexImage3D= (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");

//Get the pointer address;

University of Wales Swansea

56

Benjamin Mora

advanced features render to texture
Advanced Features: Render to texture
  • Allows rendering into an intermediate image that will be re-used in the final image.
    • Useful for (cube or spherical map) environmental mapping.
    • Mirroring effects.
    • Reflections.
    • Refractions.
    • Lighting effects.
    • Bump mapping.
    • Vertex Textures.

University of Wales Swansea

57

Benjamin Mora

advanced features shadows
Advanced Features: Shadows
  • How to efficiently compute shadows that are compatible with current graphics hardware ?
  • Two possibilities:
    • Shadow Maps.
      • See CS 307
    • Shadow Volumes.

University of Wales Swansea

58

Benjamin Mora

advanced features shadow volume
Advanced Features: Shadow Volume

Image created by Steve Leach using OpenOffice Draw (v1.9.95), 30 May 2005 for use in the Shadow Volumes article.

http://en.wikipedia.org/wiki/Shadow_volume

University of Wales Swansea

59

Benjamin Mora

advanced features shadow volume1
Advanced Features: Shadow Volume
  • Encode the surface of regions (volumes) of the scene that are located inside the penumbra.
  • Make use of the stencil test after having rendered the scene.
    • Stencil buffer initialized to 0.
    • Every fragment that passes the z-test adds +1 to the stencil value.
    • If even count at the end => object visible from light source.
  • Exact shadow contours.
  • Shadow volumes are hard to update when the scene is complex and dynamic.

University of Wales Swansea

60

Benjamin Mora

ad