// Last edited on 2003-06-26 11:17:07 by stolfi #declare mb_brick_tx = texture { pigment { bumps color_map { [ 0.0 color rgb < 0.50, 0.53, 0.55 > ] [ 1.0 color rgb < 0.45, 0.43, 0.40 > ] } } finish { diffuse 0.95 ambient 0.05 specular 0.05 roughness 0.01 } normal { granite 0.5 scale 0.1 } } #macro mb_brick(dx,dy,dz) box { < 0.003*(1+rand(RND)), -0.5*dy+0.003*(1+rand(RND)), 0.003*(1+rand(RND)) >, < dx-0.003*(1+rand(RND)), +0.5*dy-0.003*(1+rand(RND)), dz-0.003*(1+rand(RND)) > rotate 1*(2*rand(RND)-1)*x rotate 2*(0.240/dx)*(2*rand(RND)-1)*z texture { mb_brick_tx translate < rand(RND),rand(RND),rand(RND) > } } #end #macro mb_wall_section(nx,nz,bsync,L,W,H) // A brick wall section // // "nx" : effective width of wall in brick lengths (half-integer). // "nz" : height of wall in brick heights (integer). // "bsync" : brick shift for first row (0 = -L/4, 1 = +L/4). // // "L","W","H" : brick length, width, and height. #debug concat("\nmb_wall_section: nz = ", str(nz,5,0), "\n") union { #local lsync = bsync; #local i = 0; #while (i < nz) union{ #local lox = (0.5*lsync - 0.25)*L; #while (lox + L < (nx + 0.3)*L) object { mb_brick(L, W, H) translate lox*x } #local lox = lox + L; #end translate i*H*z } #local i = i + 1; #local lsync = 1 - lsync; #end } #end #macro mb_archstones(nx, L,W,H) // The stones that frame an arch whose total width is nx bricks. // // "nx" : width of window (including frame) in brick lengths (integer). // // "L","W","H" : brick length, width, and height "H". // // Note that "nx" must be at least 2. // Primitive hack: #local rin = 0.5*(nx-1.5)*L; // Inner radius of arch. #local rot = 0.5*(nx-0.5)*L; // Outer radius of arch frame. #local cx = 0.5*nx*L; // X of arch center. difference { cylinder { < cx, -0.53*W, 0>, < cx, +0.53*W, 0>, rot } cylinder { < cx, -0.54*W, 0>, < cx, +0.54*W, 0>, rin } plane { z,0 } bounded_by { box { < cx-1.001*rot, -0.531*W, 0>, < cx+1.001*rot, +0.531*W, +1.001*rot > } } texture { mb_brick_tx translate < rand(RND),rand(RND),rand(RND) > } } #end #macro mb_window_frame(nx,nz,bsync,L,W,H) // A brick wall section with a window on it. Arguments are: // // "nx" : width of wall in brick lengths (half-integer). // "nz" : total of window (including frame) in brick heights (integer). // "bsync" : brick shift for first row (0 = -L/4, 1 = +L/4). // // "L","W","H" : brick length, width, and height "H". // // The window opening is (nx-1.5)*L wide. The window is surrounded // by a frame, half-brick wide, with which starts 1/4 brick inwards // from the nominal wall boundary. The bricks are staggered by // ±0.25*L with respect to that boundary. // // Note that "nx" must be at least 2 and "nz" must be at least 4. #local rin = 0.5*(nx-1.5)*L; // Inner radius of arch. #local rot = rin + 0.40*L; // Approx outer radius of arch frame. #local nza = floor(nz - rot/H); // Brick rows below arch center. #local nzs = min(2,ceil(nz/15.0)); // Height of window sill. #local cx = 0.5*nx*L; // X of arch center. #local cz = nza*H; // Z of arch center. #local lsync = bsync; #local rsync = mod(floor(lsync + 2*nx + 0.5),2); // Sync at right end. #debug concat("\nnx = ", str(nx,4,1)) #debug concat(" lsync = ", str(lsync,1,0)) #debug concat(" rsync = ", str(rsync,1,0), "\n") union { // Brick rows 0..nzs-1 are a monolithic window sill: object { mb_brick((nx-0.5)*L, 1.05*W, nzs*H) translate 0.25*L*x } #local i = 0; #while (i < nz) #local bz = i*H; union { #if (i < nzs) // Brick rows 0 to nzs-1 are truncated by window sill #if (lsync = 0) object { mb_brick(0.5*L, W, H) translate -0.25*L*x } #end #if (rsync = 1) object { mb_brick(0.5*L, W, H) translate (nx-0.25)*L*x } #end #end #if ((i >= nzs) & (i < nza)) // Brick rows nzs to nza-1 are the straight part of window #if (lsync = 0) object { mb_brick(L, W, H) translate -0.25*L*x } #else object { mb_brick(0.5*L, W, H) translate +0.25*L*x } #end #if (rsync = 0) object { mb_brick(0.5*L, W, H) translate (nx-0.75)*L*x } #else object { mb_brick(L, W, H) translate (nx-0.75)*L*x } #end #end #if (i >= nza) // Round part of window // Generate row "i" of bricks interrupted by round arch #local thisx = (0.5*lsync - 0.25)*L; #local maxx = (nx + 0.5*rsync - 0.25)*L; #while (thisx < maxx - 0.2*L) // Ideal brick would span [thisx _ nextx] #local nextx = thisx + L; // Try to generate a whole brick #local lox = thisx; #local hix = min(nextx, maxx); // Find point of brick nearest to arc center: #if ((lox < cx) & (hix > cx)) #local nearx = cx; #else #if (hix <= cx) #local nearx = hix; #else #local nearx = lox; #end #end // If the whole brick does not fit outside the frame, halve it: #while ((hix > lox + 0.1*L) & ((nearx-cx)*(nearx-cx) + (bz-cz)*(bz-cz) < rot*rot)) // Didn't fit, try to shorten: #if (lox <= cx) #local hix = min(hix - 0.5*L, cx); #local nearx = hix; #else #local lox = max(cx, lox + 0.5*L); #local nearx = lox; #end #end // If anything is left of the brick, output it: #if (hix > lox + 0.1*L) object { mb_brick(hix-lox, W, H) translate lox*x } #end #local thisx = thisx + L; #end #end translate bz*z } #local i = i + 1; #local lsync = 1 - lsync; #local rsync = 1 - rsync; #end // Now generate the arch stones object { mb_archstones(nx, L,W,H) translate nza*H*z } } #end #declare mb_grille_tx = texture { pigment { color rgb < 0.35, 0.33, 0.25 > } finish { diffuse 0.85 ambient 0.05 specular 0.15 roughness 0.01 } normal { granite 0.1 } scale 0.05 } #macro mb_window_grille(nx,nz,r,L,W,H) // Window grille given the total window's // width "nx" and height "nz" (in bricks, including frame) // and the bar radius "r". The grille is positioned // inside the window. #local sx = (nx - 1.5)*L; #local sz = (nz - 4)*H; #debug concat("\nmb_window_grille: r = ", str(r,8,4), "\n") union { cylinder { < -sx/6, 0, -0.05*sz >, < -sx/6, 0, +1.05*sz >, r } cylinder { < +sx/6, 0, -0.05*sz >, < +sx/6, 0, +1.05*sz >, r } #local n = int(sz/(sx/3) + 0.5); #local dz = sz / n; #local p = dz; #while (p < 0.999*sz) cylinder { < -0.505*sx, 0, p >, < +0.505*sx, 0, p >, r } #local p = p + dz; #end texture { mb_grille_tx } translate 0.5*nx*L*x + 2*H*z } #end #macro mb_wnd_wall_section(wall_nx,wall_nz,wnd_dz,wnd_nz,bsync,r,L,W,H) // "bsync" : brick shift for first row (0 = -L/4, 1 = +L/4). // A wall section of width "wall_nx" and height "wall_nz", // with a window at height "wnd_dz" and height "wnd_nz". // All dimensions are in bricks; the window dims include the frame. // If "r" is nonzero, adds a grille with bars of radius "r". #debug concat("\nmb_wnd_wall_section: r = ", str(r,8,4), "\n") #local wnd_tz = wnd_dz + wnd_nz; union { object{ mb_wall_section(wall_nx, wnd_dz, bsync, L,W,H) } union{ object{ mb_window_frame(wall_nx, wnd_nz, mod(bsync+wnd_dz,2), L,W,H) } #if (r > 0) object{ mb_window_grille(wall_nx, wnd_nz, r, L,W,H) } #end translate wnd_dz*H*z } object{ mb_wall_section(wall_nx, wall_nz - wnd_tz, mod(bsync+wnd_tz,2), L,W,H) translate wnd_tz*H*z } } #end