diff options
Diffstat (limited to 'progs')
-rw-r--r-- | progs/Makefile | 26 | ||||
-rw-r--r-- | progs/demos/fogcoord.c | 2 | ||||
-rw-r--r-- | progs/demos/projtex.c | 1 | ||||
-rwxr-xr-x | progs/fp/Makefile | 1 | ||||
-rw-r--r-- | progs/fp/tri-inv.c | 2 | ||||
-rw-r--r-- | progs/glsl/CH11-bumpmaptex.frag | 47 | ||||
-rw-r--r-- | progs/glsl/bump.c | 55 | ||||
-rw-r--r-- | progs/glsl/deriv.c | 15 | ||||
-rw-r--r-- | progs/samples/Makefile | 2 | ||||
-rw-r--r-- | progs/samples/rgbtoppm.c | 11 | ||||
-rw-r--r-- | progs/tests/Makefile | 1 | ||||
-rw-r--r-- | progs/tests/prog_parameter.c | 5 | ||||
-rw-r--r-- | progs/tests/texdown.c | 3 | ||||
-rw-r--r-- | progs/tests/texleak.c | 140 | ||||
-rw-r--r-- | progs/util/readtex.c | 7 | ||||
-rw-r--r-- | progs/vpglsl/vp-tris.c | 12 | ||||
-rw-r--r-- | progs/xdemos/glxinfo.c | 15 |
17 files changed, 308 insertions, 37 deletions
diff --git a/progs/Makefile b/progs/Makefile index d5852fa416..5bc444e952 100644 --- a/progs/Makefile +++ b/progs/Makefile @@ -4,7 +4,7 @@ TOP = .. include $(TOP)/configs/current -SUBDIRS = "$(strip "$(PROGRAM_DIRS)")" +SUBDIRS = $(PROGRAM_DIRS) default: message subdirs @@ -15,22 +15,18 @@ message: subdirs: - @if test -n "$(SUBDIRS)" ; then \ - for dir in $(SUBDIRS) ; do \ - if [ -d $$dir ] ; then \ - (cd $$dir && $(MAKE)) || exit 1 ; \ - fi \ - done \ - fi + @list='$(SUBDIRS)'; for dir in $$list ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE)) || exit 1 ; \ + fi \ + done # Dummy install target install: clean: - -@if test -n "$(SUBDIRS)" ; then \ - for dir in $(SUBDIRS) tests ; do \ - if [ -d $$dir ] ; then \ - (cd $$dir && $(MAKE) clean) ; \ - fi \ - done \ - fi + @list='$(SUBDIRS)'; for dir in $$list tests ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE) clean) ; \ + fi \ + done diff --git a/progs/demos/fogcoord.c b/progs/demos/fogcoord.c index 6f50993c98..7d5c11aabf 100644 --- a/progs/demos/fogcoord.c +++ b/progs/demos/fogcoord.c @@ -15,8 +15,6 @@ #define DEPTH 5.0f -static PFNGLFOGCOORDPOINTEREXTPROC glFogCoordPointer_ext; - static GLfloat camz; static GLint fogMode; diff --git a/progs/demos/projtex.c b/progs/demos/projtex.c index ad205c7413..503cf5de08 100644 --- a/progs/demos/projtex.c +++ b/progs/demos/projtex.c @@ -248,6 +248,7 @@ loadImageTextures(void) free(texData3); free(texData4); + free(image); } } diff --git a/progs/fp/Makefile b/progs/fp/Makefile index 681928cf26..d77cd32b4d 100755 --- a/progs/fp/Makefile +++ b/progs/fp/Makefile @@ -17,6 +17,7 @@ SOURCES = \ tri-depth2.c \ tri-depthwrite.c \ tri-depthwrite2.c \ + tri-inv.c \ tri-param.c \ fp-tri.c diff --git a/progs/fp/tri-inv.c b/progs/fp/tri-inv.c index 7e8d8c5ce2..7e490fa61c 100644 --- a/progs/fp/tri-inv.c +++ b/progs/fp/tri-inv.c @@ -56,7 +56,7 @@ static void Key(unsigned char key, int x, int y) case 27: exit(1); default: - return; + break; } glutPostRedisplay(); diff --git a/progs/glsl/CH11-bumpmaptex.frag b/progs/glsl/CH11-bumpmaptex.frag new file mode 100644 index 0000000000..b1f93b784d --- /dev/null +++ b/progs/glsl/CH11-bumpmaptex.frag @@ -0,0 +1,47 @@ +// +// Fragment shader for procedural bumps +// +// Authors: John Kessenich, Randi Rost +// +// Copyright (c) 2002-2006 3Dlabs Inc. Ltd. +// +// See 3Dlabs-License.txt for license information +// +// Texture mapping/modulation added by Brian Paul +// + +varying vec3 LightDir; +varying vec3 EyeDir; + +uniform float BumpDensity; // = 16.0 +uniform float BumpSize; // = 0.15 +uniform float SpecularFactor; // = 0.5 + +sampler2D Tex; + +void main() +{ + vec3 ambient = vec3(0.25); + vec3 litColor; + vec2 c = BumpDensity * gl_TexCoord[0].st; + vec2 p = fract(c) - vec2(0.5); + + float d, f; + d = p.x * p.x + p.y * p.y; + f = inversesqrt(d + 1.0); + + if (d >= BumpSize) + { p = vec2(0.0); f = 1.0; } + + vec3 SurfaceColor = texture2D(Tex, gl_TexCoord[0].st).xyz; + + vec3 normDelta = vec3(p.x, p.y, 1.0) * f; + litColor = SurfaceColor * (ambient + max(dot(normDelta, LightDir), 0.0)); + vec3 reflectDir = reflect(LightDir, normDelta); + + float spec = max(dot(EyeDir, reflectDir), 0.0); + spec *= SpecularFactor; + litColor = min(litColor + spec, vec3(1.0)); + + gl_FragColor = vec4(litColor, 1.0); +} diff --git a/progs/glsl/bump.c b/progs/glsl/bump.c index 50a0900f1c..e31afab939 100644 --- a/progs/glsl/bump.c +++ b/progs/glsl/bump.c @@ -12,15 +12,20 @@ #include <GL/glew.h> #include <GL/glut.h> #include "shaderutil.h" +#include "readtex.h" static char *FragProgFile = "CH11-bumpmap.frag"; +static char *FragTexProgFile = "CH11-bumpmaptex.frag"; static char *VertProgFile = "CH11-bumpmap.vert"; +static char *TextureFile = "../images/tile.rgb"; /* program/shader objects */ static GLuint fragShader; +static GLuint fragTexShader; static GLuint vertShader; static GLuint program; +static GLuint texProgram; static struct uniform_info Uniforms[] = { @@ -32,13 +37,26 @@ static struct uniform_info Uniforms[] = { END_OF_UNIFORMS }; +static struct uniform_info TexUniforms[] = { + { "LightPosition", 1, GL_FLOAT_VEC3, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 }, + { "Tex", 1, GL_INT, { 0, 0, 0, 0 }, -1 }, + { "BumpDensity", 1, GL_FLOAT, { 10.0, 0, 0, 0 }, -1 }, + { "BumpSize", 1, GL_FLOAT, { 0.125, 0, 0, 0 }, -1 }, + { "SpecularFactor", 1, GL_FLOAT, { 0.5, 0, 0, 0 }, -1 }, + END_OF_UNIFORMS +}; + static GLint win = 0; static GLfloat xRot = 20.0f, yRot = 0.0f, zRot = 0.0f; static GLint tangentAttrib; +static GLint tangentAttribTex; + +static GLuint Texture; static GLboolean Anim = GL_FALSE; +static GLboolean Textured = GL_FALSE; static void @@ -135,6 +153,11 @@ Redisplay(void) glRotatef(yRot, 0.0f, 1.0f, 0.0f); glRotatef(zRot, 0.0f, 0.0f, 1.0f); + if (Textured) + glUseProgram(texProgram); + else + glUseProgram(program); + Cube(1.5); glPopMatrix(); @@ -163,8 +186,10 @@ static void CleanUp(void) { glDeleteShader(fragShader); + glDeleteShader(fragTexShader); glDeleteShader(vertShader); glDeleteProgram(program); + glDeleteProgram(texProgram); glutDestroyWindow(win); } @@ -181,6 +206,9 @@ Key(unsigned char key, int x, int y) Anim = !Anim; glutIdleFunc(Anim ? Idle : NULL); break; + case 't': + Textured = !Textured; + break; case 'z': zRot += step; break; @@ -254,6 +282,26 @@ Init(void) CheckError(__LINE__); + + /* + * As above, but fragment shader also uses a texture map. + */ + fragTexShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragTexProgFile); + texProgram = LinkShaders(vertShader, fragTexShader); + glUseProgram(texProgram); + assert(glIsProgram(texProgram)); + assert(glIsShader(fragTexShader)); + SetUniformValues(texProgram, TexUniforms); + PrintUniforms(TexUniforms); + + /* + * Load tex image. + */ + glGenTextures(1, &Texture); + glBindTexture(GL_TEXTURE_2D, Texture); + LoadRGBMipmaps(TextureFile, GL_RGB); + + glClearColor(0.4f, 0.4f, 0.8f, 0.0f); glEnable(GL_DEPTH_TEST); @@ -268,10 +316,13 @@ ParseOptions(int argc, char *argv[]) int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-fs") == 0) { - FragProgFile = argv[i+1]; + FragProgFile = argv[++i]; } else if (strcmp(argv[i], "-vs") == 0) { - VertProgFile = argv[i+1]; + VertProgFile = argv[++i]; + } + else if (strcmp(argv[i], "-t") == 0) { + TextureFile = argv[++i]; } } } diff --git a/progs/glsl/deriv.c b/progs/glsl/deriv.c index 30f2b75fef..588246b71a 100644 --- a/progs/glsl/deriv.c +++ b/progs/glsl/deriv.c @@ -27,11 +27,15 @@ static GLuint SphereList, RectList, CurList; static GLint win = 0; static GLboolean anim = GL_TRUE; static GLfloat xRot = 0.0f, yRot = 0.0f; +static GLint WinSize[2]; +static GLint WinSizeUniform = -1; static void Redisplay(void) { + glUniform2iv(WinSizeUniform, 1, WinSize); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); @@ -55,6 +59,8 @@ Idle(void) static void Reshape(int width, int height) { + WinSize[0] = width; + WinSize[1] = height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -163,8 +169,10 @@ static void Init(void) { static const char *fragShaderText = + "uniform ivec2 WinSize; \n" "void main() {\n" - " gl_FragColor = abs(dFdy(gl_TexCoord[0])) * 50.0;\n" + " vec2 d = dFdy(gl_TexCoord[0].xy) * vec2(WinSize); \n" + " gl_FragColor = vec4(d.x, d.y, 0.0, 1.0);\n" " // gl_FragColor = gl_TexCoord[0];\n" "}\n"; static const char *vertShaderText = @@ -181,6 +189,7 @@ Init(void) program = LinkShaders(vertShader, fragShader); glUseProgram(program); + WinSizeUniform = glGetUniformLocation(program, "WinSize"); /*assert(glGetError() == 0);*/ @@ -220,8 +229,10 @@ ParseOptions(int argc, char *argv[]) int main(int argc, char *argv[]) { + WinSize[0] = WinSize[1] = 200; + glutInit(&argc, argv); - glutInitWindowSize(200, 200); + glutInitWindowSize(WinSize[0], WinSize[1]); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); win = glutCreateWindow(argv[0]); glewInit(); diff --git a/progs/samples/Makefile b/progs/samples/Makefile index b300e38b9c..64fa47addb 100644 --- a/progs/samples/Makefile +++ b/progs/samples/Makefile @@ -10,7 +10,7 @@ LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(T LIBS = -L$(TOP)/$(LIB_DIR) -l$(GLUT_LIB) -l$(GLEW_LIB) -l$(GLU_LIB) -l$(GL_LIB) $(APP_LIB_DEPS) PROGS = accum bitmap1 bitmap2 blendeq blendxor copy cursor depth eval fog \ - font line logo nurb olympic overlay point prim quad select \ + font line logo nurb olympic overlay point prim rgbtoppm quad select \ shape sphere star stencil stretch texture tri wave diff --git a/progs/samples/rgbtoppm.c b/progs/samples/rgbtoppm.c index 116d9a8cfa..dcb74228df 100644 --- a/progs/samples/rgbtoppm.c +++ b/progs/samples/rgbtoppm.c @@ -86,13 +86,19 @@ static ImageRec *ImageOpen(char *fileName) exit(1); } if ((image->file = fopen(fileName, "rb")) == NULL) { - return NULL; + free(image); + return NULL; } fread(image, 1, 12, image->file); if (swapFlag) { - ConvertShort(&image->imagic, 6); + ConvertShort(&image->imagic, 1); + ConvertShort(&image->type, 1); + ConvertShort(&image->dim, 1); + ConvertShort(&image->xsize, 1); + ConvertShort(&image->ysize, 1); + ConvertShort(&image->zsize, 1); } image->tmp = (unsigned char *)malloc(image->xsize*256); @@ -224,6 +230,7 @@ read_rgb_texture(char *name, int *width, int *height) if (gbuf) free(gbuf); if (bbuf) free(bbuf); if (abuf) free(abuf); + ImageClose(image); return NULL; } ptr = base; diff --git a/progs/tests/Makefile b/progs/tests/Makefile index 197e14d5b0..3e2541186b 100644 --- a/progs/tests/Makefile +++ b/progs/tests/Makefile @@ -98,6 +98,7 @@ SOURCES = \ texdown \ texfilt.c \ texgenmix.c \ + texleak.c \ texline.c \ texobj.c \ texobjshare.c \ diff --git a/progs/tests/prog_parameter.c b/progs/tests/prog_parameter.c index 0241f3a249..2de7e2994a 100644 --- a/progs/tests/prog_parameter.c +++ b/progs/tests/prog_parameter.c @@ -192,6 +192,7 @@ static void Init( void ) GLfloat * params; GLint max_program_env_parameters; GLint max_program_local_parameters; + int i; printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); @@ -238,6 +239,10 @@ static void Init( void ) params = malloc(max_program_env_parameters * 4 * sizeof(GLfloat)); + for (i = 0; i < max_program_env_parameters * 4; i++) { + params[i] = 0.0F; + } + pass &= set_parameter_batch(max_program_env_parameters, params, "Env", program_env_parameter4fv, program_env_parameters4fv, diff --git a/progs/tests/texdown.c b/progs/tests/texdown.c index e6881d39a0..92df01b83d 100644 --- a/progs/tests/texdown.c +++ b/progs/tests/texdown.c @@ -162,7 +162,7 @@ MeasureDownloadRate(void) const int image_bytes = align(w * h * BytesPerTexel(Format), ALIGN); const int bytes = image_bytes * NR_TEXOBJ; GLubyte *orig_texImage, *orig_getImage; - GLubyte *texImage, *getImage; + GLubyte *texImage; GLdouble t0, t1, time; int count; int i; @@ -184,7 +184,6 @@ MeasureDownloadRate(void) printf("alloc %p %p\n", orig_texImage, orig_getImage); texImage = (GLubyte *)align((unsigned long)orig_texImage, ALIGN); - getImage = (GLubyte *)align((unsigned long)orig_getImage, ALIGN); for (i = 1; !(((unsigned long)texImage) & i); i<<=1) ; diff --git a/progs/tests/texleak.c b/progs/tests/texleak.c new file mode 100644 index 0000000000..5cf4ff3239 --- /dev/null +++ b/progs/tests/texleak.c @@ -0,0 +1,140 @@ +/* + * 'Texture leak' test + * + * Allocates and uses an additional texture of the maximum supported size for + * each frame. This tests the system's ability to cope with using increasing + * amounts of texture memory. + * + * Michel Dänzer July 2009 This program is in the public domain. + */ + + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> +#include <GL/glew.h> +#include <GL/glut.h> + + +GLint size; +GLvoid *image; +static GLuint numTexObj; +static GLuint *texObj; + + +static void Idle( void ) +{ + glutPostRedisplay(); +} + + +static void DrawObject(void) +{ + static const GLfloat tex_coords[] = { 0.0, 0.0, 1.0, 1.0, 0.0 }; + static const GLfloat vtx_coords[] = { -1.0, -1.0, 1.0, 1.0, -1.0 }; + GLint i, j; + + glEnable(GL_TEXTURE_2D); + + for (i = 0; i < numTexObj; i++) { + glBindTexture(GL_TEXTURE_2D, texObj[i]); + glBegin(GL_QUADS); + for (j = 0; j < 4; j++ ) { + glTexCoord2f(tex_coords[j], tex_coords[j+1]); + glVertex2f( vtx_coords[j], vtx_coords[j+1] ); + } + glEnd(); + } +} + + +static void Display( void ) +{ + struct timeval start, end; + + texObj = realloc(texObj, ++numTexObj * sizeof(*texObj)); + + /* allocate a texture object */ + glGenTextures(1, texObj + (numTexObj - 1)); + + glBindTexture(GL_TEXTURE_2D, texObj[numTexObj - 1]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + memset(image, (16 * numTexObj) & 0xff, 4 * size * size); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image); + + gettimeofday(&start, NULL); + + glClear( GL_COLOR_BUFFER_BIT ); + + glPushMatrix(); + glScalef(5.0, 5.0, 5.0); + DrawObject(); + glPopMatrix(); + + glutSwapBuffers(); + + glFinish(); + gettimeofday(&end, NULL); + printf("Rendering frame took %lu ms using %u MB of textures\n", + end.tv_sec * 1000 + end.tv_usec / 1000 - start.tv_sec * 1000 - + start.tv_usec / 1000, numTexObj * 4 * size / 1024 * size / 1024); + + sleep(1); +} + + +static void Reshape( int width, int height ) +{ + glViewport( 0, 0, width, height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( -6.0, 6.0, -6.0, 6.0, 10.0, 100.0 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -70.0 ); +} + + +static void Init( int argc, char *argv[] ) +{ + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size); + printf("%d x %d max texture size\n", size, size); + + image = malloc(4 * size * size); + if (!image) { + fprintf(stderr, "Failed to allocate %u bytes of memory\n", 4 * size * size); + exit(1); + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glShadeModel(GL_FLAT); + glClearColor(0.3, 0.3, 0.4, 1.0); + + Idle(); +} + + +int main( int argc, char *argv[] ) +{ + glutInit( &argc, argv ); + glutInitWindowSize( 300, 300 ); + glutInitWindowPosition( 0, 0 ); + glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); + glutCreateWindow(argv[0] ); + glewInit(); + + Init( argc, argv ); + + glutReshapeFunc( Reshape ); + glutDisplayFunc( Display ); + glutIdleFunc(Idle); + + glutMainLoop(); + return 0; +} diff --git a/progs/util/readtex.c b/progs/util/readtex.c index 81cb626e91..d1c50a494a 100644 --- a/progs/util/readtex.c +++ b/progs/util/readtex.c @@ -117,7 +117,12 @@ static rawImageRec *RawImageOpen(const char *fileName) fread(raw, 1, 12, raw->file); if (swapFlag) { - ConvertShort(&raw->imagic, 6); + ConvertShort(&raw->imagic, 1); + ConvertShort(&raw->type, 1); + ConvertShort(&raw->dim, 1); + ConvertShort(&raw->sizeX, 1); + ConvertShort(&raw->sizeY, 1); + ConvertShort(&raw->sizeZ, 1); } raw->tmp = (unsigned char *)malloc(raw->sizeX*256); diff --git a/progs/vpglsl/vp-tris.c b/progs/vpglsl/vp-tris.c index b2b0508091..6a1fa3d3bf 100644 --- a/progs/vpglsl/vp-tris.c +++ b/progs/vpglsl/vp-tris.c @@ -84,9 +84,9 @@ static void check_link(GLuint prog) static void setup_uniforms() { { - GLuint loc1f = glGetUniformLocationARB(program, "Offset1f"); - GLuint loc2f = glGetUniformLocationARB(program, "Offset2f"); - GLuint loc4f = glGetUniformLocationARB(program, "Offset4f"); + GLint loc1f = glGetUniformLocationARB(program, "Offset1f"); + GLint loc2f = glGetUniformLocationARB(program, "Offset2f"); + GLint loc4f = glGetUniformLocationARB(program, "Offset4f"); GLfloat vecKer[] = { 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, @@ -105,9 +105,9 @@ static void setup_uniforms() } { - GLuint loc1f = glGetUniformLocationARB(program, "KernelValue1f"); - GLuint loc2f = glGetUniformLocationARB(program, "KernelValue2f"); - GLuint loc4f = glGetUniformLocationARB(program, "KernelValue4f"); + GLint loc1f = glGetUniformLocationARB(program, "KernelValue1f"); + GLint loc2f = glGetUniformLocationARB(program, "KernelValue2f"); + GLint loc4f = glGetUniformLocationARB(program, "KernelValue4f"); GLfloat vecKer[] = { 1.0, 0.0, 0.0, 0.25, 0.0, 1.0, 0.0, 0.25, diff --git a/progs/xdemos/glxinfo.c b/progs/xdemos/glxinfo.c index b182a3091d..23df82f6f9 100644 --- a/progs/xdemos/glxinfo.c +++ b/progs/xdemos/glxinfo.c @@ -401,6 +401,10 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits) root = RootWindow(dpy, scrnum); + /* + * Find a basic GLX visual. We'll then create a rendering context and + * query various info strings. + */ visinfo = glXChooseVisual(dpy, scrnum, attribSingle); if (!visinfo) visinfo = glXChooseVisual(dpy, scrnum, attribDouble); @@ -409,24 +413,29 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits) ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect ); #ifdef GLX_VERSION_1_3 - { + /* Try glXChooseFBConfig() if glXChooseVisual didn't work. + * XXX when would that happen? + */ + if (!visinfo) { int fbAttribSingle[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, GL_TRUE, + GLX_DOUBLEBUFFER, GL_FALSE, None }; int fbAttribDouble[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, GL_TRUE, None }; GLXFBConfig *configs = NULL; int nConfigs; - if (!visinfo) + configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs); + if (!configs) configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs); if (configs) { |