'From Squeak3.2alpha of 10 October 2001 [latest update: #4599] on 21 December 2001 at 3:00:40 pm'! "Change Set: Avatar Date: 21 December 2001 Author: Luciano This change set contains an animated face based on Waters' muscle model. Each avatar has a set of control parameters for facial muscles, eyeballs, eyelids, and mouth. Try: AvatarBuilder new openInWorld "! Object subclass: #Avatar instanceVariableNames: 'muscles jaw leftEye rightEye ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! !Avatar commentStamp: '' prior: 0! My instances are 3D avatars based on the Waters' muscle model. Each avatar has a set of control parameters for facial muscles, eyeballs, eyelids, and mouth. [1] Waters, K. "A muscle model for animating three-dimensional facial expression.", IEEE Computer Graphics, 21(4)! Object subclass: #AvatarBuilder instanceVariableNames: 'avatar vertices faces faceMesh leftEyeballMesh rightEyeballMesh eyeballTexture ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! AvatarBuilder class instanceVariableNames: ''! AlignmentMorph subclass: #AvatarControlMorph instanceVariableNames: 'avatar head scene left right ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Support'! Object subclass: #Eye instanceVariableNames: 'mesh center rotation upperEyelid lowerEyelid ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! Eye class instanceVariableNames: ''! Object subclass: #Eyelid instanceVariableNames: 'mesh indices angle direction ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! Eyelid class instanceVariableNames: ''! Morph subclass: #Head3DMorph instanceVariableNames: 'scene head queue ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Support'! Head3DMorph class instanceVariableNames: ''! Object subclass: #Jaw instanceVariableNames: 'mesh indices angle ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! Jaw class instanceVariableNames: ''! Object subclass: #Muscle instanceVariableNames: 'mesh name head tail zone start end clamp contraction indices directions ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! !Muscle commentStamp: '' prior: 0! My instances model facial muscles that deform a B3DIndexedMesh.! Muscle class instanceVariableNames: ''! Object subclass: #SphincterMuscle instanceVariableNames: 'name center axis1 axis2 axis3 zone contraction indices directions ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! SphincterMuscle class instanceVariableNames: ''! SimpleSliderMorph subclass: #UpdatingSimpleSliderMorph instanceVariableNames: 'getValueSelector ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Support'! Object subclass: #Viseme instanceVariableNames: 'contractions ' classVariableNames: '' poolDictionaries: '' category: 'Avatars-Kernel'! Viseme class instanceVariableNames: ''! !AdvancedB3DSceneMorph methodsFor: 'accessing' stamp: 'len 1/15/2001 21:43'! scene: aScene super scene: ("self updateSceneWithDefaults:" aScene). self updateUpVectorForCamera: self scene defaultCamera. self updateHeadlight. self changed! ! !AdvancedB3DSceneMorph methodsFor: 'private' stamp: 'len 1/15/2001 21:32'! updateSceneWithDefaults: myScene | headLight mat | myScene lights at: 'Ambient1' put: (B3DAmbientLight color: (Color gray: 0.2)). headLight := B3DSpotLight new. headLight position: myScene defaultCamera position. headLight target: myScene defaultCamera target. headLight lightColor: (B3DMaterialColor color: (Color gray: 0.7)). headLight attenuation: (B3DLightAttenuation constant: 1.0 linear: 0.0 squared: 0.0). headLight minAngle: 80. headLight maxAngle: 90. myScene lights at: '$HeadLight$' put: headLight copy. mat := B3DMaterial new. mat diffusePart: (Color gray: 0.25). mat ambientPart: (Color gray: 0.01). myScene objects do: [:o| o material: mat]. ^myScene! ! !Avatar methodsFor: 'accessing' stamp: 'len 9/11/1999 03:41'! jaw ^ jaw! ! !Avatar methodsFor: 'accessing' stamp: 'len 1/29/2001 11:49'! jaw: aJaw jaw _ aJaw! ! !Avatar methodsFor: 'accessing' stamp: 'len 2/27/2000 21:36'! leftEye ^ leftEye! ! !Avatar methodsFor: 'accessing' stamp: 'len 1/29/2001 11:49'! leftEye: anEye leftEye _ anEye! ! !Avatar methodsFor: 'accessing' stamp: 'len 1/29/2001 12:00'! muscles ^ muscles! ! !Avatar methodsFor: 'accessing' stamp: 'len 1/29/2001 12:00'! muscles: aCollection muscles _ aCollection! ! !Avatar methodsFor: 'accessing' stamp: 'len 2/27/2000 21:36'! rightEye ^ rightEye! ! !Avatar methodsFor: 'accessing' stamp: 'len 1/30/2001 17:01'! rightEye: anEye rightEye _ anEye! ! !Avatar methodsFor: 'actions' stamp: 'len 1/29/2001 12:31'! relax jaw relax. self muscles do: [ :each | each relax]! ! !AvatarBuilder methodsFor: 'initialization' stamp: 'len 1/13/2001 04:00'! initialize self initializeVertices. self initializeFaces! ! !AvatarBuilder methodsFor: 'initialization' stamp: 'len 1/13/2001 18:37'! initializeFaces | facesStream p1 p2 p3 p4 half | facesStream _ WriteStream on: (B3DIndexedTriangleArray new: self facesData size). half _ vertices size // 2. "Read in the faces" self facesData do: [ :words | p1 _ words at: 1. p2 _ words at: 2. p3 _ words at: 3. p4 _ words at: 4. p1 = 1000 ifTrue: [facesStream nextPut: (B3DIndexedTriangle with: p2 with: p3 with: p4); nextPut: (B3DIndexedTriangle with: p3+half with: p2+half with: p4+half)] ifFalse: [facesStream nextPut: (B3DIndexedTriangle with: p1 with: p2 with: p3); nextPut: (B3DIndexedTriangle with: p2+half with: p1+half with: p3+half); nextPut: (B3DIndexedTriangle with: p1 with: p3 with: p4); nextPut: (B3DIndexedTriangle with: p3+half with: p1+half with: p4+half)]]. "Create the faces array" faces _ facesStream contents! ! !AvatarBuilder methodsFor: 'initialization' stamp: 'len 1/13/2001 18:37'! initializeVertices | count entry | count _ self halfVerticesData size. vertices _ B3DVector3Array new: count * 2. 1 to: count do: [ :index | entry _ self halfVerticesData at: index. vertices at: index put: (B3DVector3 x: entry first y: entry second z: entry third); at: count + index put: (B3DVector3 x: entry first negated y: entry second z: entry third)]! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/29/2001 12:35'! faceMesh ^ faceMesh ifNil: [faceMesh _ B3DIndexedTriangleMesh new vertices: vertices; faces: faces; texCoords: self textureCoordinates; faceNormals; vertexNormals; yourself]! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/13/2001 18:54'! facesData ^ #((1 2 5 4) (2 3 6 5) (7 4 5 8) (8 5 6 9) (1000 11 8 9) (10 7 8 11) (6 3 14 13) (9 6 13 12) (1000 11 9 12) (11 12 17 18) (12 13 16 17) (13 14 15 16) (16 15 25 24) (1000 16 24 23) (17 16 23 22) (18 17 22 21) (1000 19 11 18) (20 19 18 21) (24 25 26 27) (23 24 27 28) (22 23 28 29) (21 22 29 30) (32 20 21 31) (31 21 30 35) (35 30 29 36) (29 28 37 36) (28 27 38 37) (27 26 39 38) (38 39 40 41) (37 38 41 42) (36 37 42 43) (35 36 43 44) (34 31 35 44) (33 32 31 34) (45 33 34 46) (46 34 44 47) (47 44 43 48) (48 43 42 49) (42 41 50 49) (41 40 51 50) (50 51 64 63) (49 50 63 62) (48 49 62 61) (1000 47 48 61) (63 64 65 66) (66 65 77 76) (67 66 76 75) (62 63 66 67) (73 67 75 74) (68 62 67 73) (60 61 62 68) (52 47 61 60) (53 46 47 52) (54 45 46 53) (55 54 53 56) (1000 58 55 56) (1000 58 56 57) (56 53 52 57) (1000 58 57 59) (57 52 60 59) (58 59 69 70) (59 60 68 69) (70 69 72 71) (69 68 73 72) (1000 72 73 74) (1000 58 146 55) (146 145 54 55) (145 144 45 54) (1000 144 142 45) (142 141 33 45) (141 98 32 33) (98 97 20 32) (97 89 19 20) (1000 89 87 19) (1000 19 87 11) (87 88 10 11) (87 85 86 88) (1000 87 84 85) (84 81 82 85) (85 82 83 86) (81 80 79 82) (82 79 78 83) (89 90 84 87) (90 91 81 84) (91 92 80 81) (94 93 92 91) (1000 95 94 91) (96 95 91 90) (97 96 90 89) (98 99 96 97) (99 100 95 96) (100 101 102 95) (102 103 94 95) (103 104 93 94) (106 105 104 103) (1000 102 106 103) (1000 107 106 102) (1000 109 101 100) (1000 110 109 100) (111 110 100 112) (111 117 118 110) (110 118 108 109) (118 119 107 109) (119 120 106 107) (120 121 105 106) (123 122 121 120) (124 123 120 119) (117 124 119 118) (115 116 117 111) (113 112 100 99) (141 113 99 98) (114 115 111 112) (1000 114 112 113) (116 125 124 117) (1000 124 127 123) (127 128 122 123) (126 129 128 127) (125 126 127 124) (131 130 129 126) (132 131 126 125) (115 132 125 116) (134 135 130 131) (133 134 131 132) (133 132 115 114) (139 114 113 140) (140 113 141 142) (1000 143 140 142) (1000 144 143 142) (1000 148 144 145) (170 148 145 146) (1000 147 170 146) (147 171 169 170) (169 149 148 170) (149 150 144 148) (150 151 143 144) (151 152 140 143) (152 153 139 140) (139 138 133 114) (1000 153 138 139) (138 137 134 133) (137 136 135 134) (156 157 136 137) (155 156 137 138) (154 155 138 153) (1000 152 154 153) (159 158 157 156) (160 159 156 155) (161 160 155 154) (163 162 161 154) (164 163 154 152) (165 164 152 151) (166 165 151 150) (167 166 150 149) (169 168 167 149) (171 174 168 169) (174 177 178 168) (168 178 179 167) (179 180 166 167) (180 181 165 166) (181 182 164 165) (182 183 163 164) (183 184 162 163) (1000 184 185 162) (185 186 161 162) (186 187 160 161) (187 188 159 160) (188 189 158 159) (191 190 189 188) (192 191 188 187) (193 192 187 186) (194 193 186 185) (214 193 194 195) (214 207 192 193) (208 207 214 213) (213 214 195 196) (212 213 196 197) (211 212 197 198) (200 211 198 199) (178 200 199 179) (177 201 200 178) (201 210 211 200) (210 209 212 211) (209 208 213 212) (206 191 192 207) (205 206 207 208) (204 205 208 209) (203 204 209 210) (202 203 210 201) (176 202 201 177) (1000 174 176 177) (1000 191 215 190) (215 228 229 190) (228 231 230 229) (231 242 243 230) (232 241 242 231) (232 231 228 227) (227 228 215 216) (216 215 191 206) (217 216 206 205) (226 227 216 217) (233 232 227 226) (240 241 232 233) (239 240 233 234) (234 233 226 225) (225 226 217 218) (218 217 205 204) (219 218 204 203) (224 225 218 219) (235 234 225 224) (238 239 234 235) (237 238 235 236) (236 235 224 223) (223 224 219 220) (221 220 202 176) (220 219 203 202) (1000 175 237 236) (1000 175 236 223) (175 223 220 221) (222 221 176 174) (1000 222 174 171) (175 221 222 173) (173 222 171 172) (1000 172 171 147) (244 245 194 185) (245 246 195 194) (246 247 196 195) (247 248 197 196) (248 249 198 197) (249 250 199 198) (250 251 179 199) (179 251 252 180) (181 180 252 253) (182 181 253 254) (183 182 254 255) (184 183 255 256) (185 184 256 244) "(1000 153 138 139)")! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/13/2001 02:34'! halfVerticesData ^ #((0 -2.28 8.875) (0 -2.456 8.98) (0 -2.701 9.005) (-0.509 -2.23 8.865) (-0.577 -2.414 8.962) (-0.585 -2.67 8.987) (-1.027 -2.201 8.544) (-1.135 -2.372 8.658) (-1.182 -2.556 8.657) (-1.57 -2.221 8.025) (-1.805 -2.354 8.037) (-1.151 -3.134 8.433) (-0.565 -3.181 8.583) (0 -3.216 8.631) (0 -3.545 8.64) (-0.582 -3.517 8.557) (-1.158 -3.443 8.329) (-1.999 -2.568 7.895) (-2.121 -2.222 7.917) (-2.395 -2.073 7.692) (-2.213 -2.797 7.639) (-1.358 -3.775 8.198) (-0.837 -3.88 8.52) (-0.59 -3.91 8.645) (0 -3.914 8.646) (0 -4.564 8.583) (-0.7 -4.532 8.584) (-1.058 -4.461 8.459) (-1.579 -4.29 8.085) (-1.995 -3.66 7.538) (-2.572 -2.969 7.1) (-2.746 -1.859 7.124) (-2.99 -1.69 6.64) (-2.751 -3.033 6.688) (-2.147 -4.156 7.145) (-1.62 -4.77 7.945) (-1.081 -4.944 8.281) (-0.699 -4.994 8.36) (0 -5.021 8.36) (0 -5.412 7.852) (-0.602 -5.444 7.853) (-0.99 -5.418 7.854) (-1.597 -5.169 7.416) (-2.342 -4.202 6.524) (-3.374 -1.344 5.866) (-3.118 -3.043 5.708) (-2.559 -4.377 5.351) (-1.6 -5.205 6.353) (-0.945 -5.501 6.834) (-0.542 -5.601 7.067) (0 -5.636 7.068) (-3.232 -3.283 3.861) (-3.686 -2.281 4.257) (-3.797 -0.831 4.703) (-4.136 -0.236 3.398) (-4.093 -1.041 3.153) (-3.959 -1.66 2.889) (-4.295 0.021 2.17) (-3.485 -2.252 2.286) (-2.74 -3.866 3.388) (-2.315 -4.57 4.819) (-0.966 -5.443 4.589) (-0.556 -5.511 4.589) (0 -5.553 4.589) (0 -7.061 3.726) (-0.436 -6.971 3.553) (-0.926 -6.872 3.196) (-2.414 -4.428 2.801) (-3.12 -3.336 1.701) (-3.204 -2.934 1.002) (-3.12 -5.511 0.149) (-3.119 -5.51 0.702) (-2.343 -6.297 1.993) (-2.389 -6.885 1.708) (-1.053 -8.199 2.359) (-0.336 -8.622 2.554) (0 -8.714 2.559) (0 -2.278 8.878) (0 -2.064 9.078) (0 -1.83 9.119) (-0.484 -1.72 9.116) (-0.512 -2.003 9.07) (-0.521 -2.231 8.876) (-1.17 -1.928 9) (-1.083 -2.093 8.703) (-1.032 -2.198 8.549) (-1.773 -2.057 8.299) (-1.572 -2.217 8.022) (-2.039 -1.735 8.072) (-1.285 -1.456 8.655) (-0.456 -1.314 8.986) (0 -1.461 8.92) (0 -0.71 8.876) (-0.237 -0.648 8.971) (-0.446 -0.648 8.971) (-1.316 -0.911 8.428) (-2.206 -1.333 7.855) (-2.274 -1.067 7.654) (-1.276 -0.534 8.239) (-0.753 -0.441 8.58) (-0.534 -0.074 8.714) (-0.191 -0.056 9.15) (-0.171 -0.426 9.051) (0 -0.441 9.053) (0 -0.232 9.57) (-0.168 -0.224 9.57) (-0.56 0.058 9.376) (-0.767 0.046 9.042) (-0.843 -0.128 8.806) (-0.978 -0.276 8.684) (-1.091 -0.204 8.513) (-0.905 -0.325 8.292) (-1.32 -0.188 8.01) (-0.895 0.194 8.202) (-1.002 0.217 8.462) (-1.077 0.307 8.703) (-1.017 0.325 8.904) (-0.9 0.099 9.033) (-0.574 0.252 9.485) (-0.118 -0.099 9.722) (0 -0.098 9.723) (0 0.512 9.855) (-0.158 0.508 9.82) (-0.587 0.55 9.557) (-0.66 0.776 9.277) (-0.242 1.137 9.532) (-0.208 0.854 9.713) (0 0.862 9.749) (0 1.192 9.559) (0 1.445 9.385) (-0.25 1.387 9.361) (-0.495 1.19 9.132) (-0.526 1.443 8.894) (-0.284 1.74 9.158) (0 1.817 9.2) (0 2.18 8.995) (-0.322 2.1 8.927) (-0.667 1.571 8.598) (-1.312 0.849 8.093) (-2.093 0.282 7.775) (-2.327 -0.805 7.56) (-3.108 -0.078 7.267) (-3.182 0.649 7.412) (-3.805 0.868 6.79) (-4.108 1.022 5.942) (-4.36 1.772 4.387) (-4.187 2.611 4.596) (-4.028 1.464 6.118) (-3.708 2.236 6.211) (-3.359 1.693 6.896) (-2.876 1.352 7.271) (-2.1 1.207 7.559) (-1.337 1.263 8.027) (-1.27 1.664 7.809) (-0.723 2.023 8.332) (-0.357 2.487 8.669) (0 2.608 8.699) (0 2.909 8.46) (-0.392 2.825 8.42) (-0.623 2.411 8.173) (-0.853 2.189 7.76) (-1.119 2.259 7.352) (-1.46 1.887 7.332) (-2.095 1.531 7.388) (-2.765 1.605 7.294) (-3.156 1.949 6.974) (-3.399 2.397 6.443) (-3.657 2.603 6.413) (-3.904 2.477 5.99) (-4.092 1.936 5.653) (-3.994 2.776 5.641) (-4.121 3.106 4.611) (-4.105 3.756 4.772) (-3.883 2.972 6.298) (-3.928 4.609 5.06) (-3.866 3.453 6.724) (-3.788 3.26 6.846) (-3.556 2.93 6.956) (-3.201 2.669 6.903) (-3.001 2.353 7.274) (-2.571 2.177 7.578) (-2.113 2.147 7.561) (-1.602 2.246 7.687) (-1.21 2.404 7.438) (-0.967 2.609 7.023) (-0.638 2.684 7.661) (-0.584 3.052 8.055) (-0.431 3.211 8.189) (0 3.262 8.208) (0 3.664 8.101) (-0.487 3.639 8.101) (-0.76 3.42 7.947) (-0.829 3.21 7.554) (-1.006 2.963 7.129) (-1.309 3.29 7.37) (-1.772 3.474 7.615) (-2.268 3.493 7.824) (-2.704 3.315 7.781) (-3.129 3.065 7.391) (-3.421 3.337 7.438) (-3.624 3.65 7.348) (-3.73 3.872 7.238) (-3.285 4.274 7.783) (-2.569 4.558 8.182) (-1.841 4.676 8.353) (-1.067 4.327 8.469) (-1.15 4.072 8.222) (-1.853 4.265 8.296) (-2.509 4.191 8.259) (-3.195 3.97 7.895) (-2.963 3.637 7.879) (-2.381 3.83 8.1) (-1.782 3.85 8.071) (-1.227 3.657 8.072) (-0.45 4.377 8.175) (-0.991 4.862 8.093) (-1.731 5.054 7.962) (-2.474 4.937 7.775) (-3.17 4.658 7.356) (-3.605 4.334 6.861) (-3.89 3.957 6.326) (-3.941 3.197 5.815) (-3.59 5.23 6.286) (-3.102 5.495 6.831) (-2.33 5.69 7.264) (-1.576 5.648 7.632) (-0.888 5.445 7.804) (-0.406 5.084 7.869) (0 4.67 7.912) (0 6.172 7.196) (-0.354 6.247 7.229) (-0.746 6.328 7.263) (-1.426 6.432 7.212) (-2.244 6.373 6.969) (-3.105 6.092 6.495) (-3.639 5.648 5.945) (-3.562 6.154 5.544) (-3.109 6.63 5.986) (-2.176 7.198 6.426) (-1.281 7.365 6.6) (-0.547 7.488 6.717) (-0.286 7.51 6.75) (0 7.522 6.764) (-0.973 2.625 7.123) (-1.041 2.87 7.229) (-1.295 3.155 7.47) (-1.693 3.288 7.715) (-2.196 3.267 7.924) (-2.545 3.146 7.881) (-2.856 2.944 7.491) (-3.091 2.634 7.003) (-2.846 2.481 7.474) (-2.383 2.398 7.878) (-2.012 2.37 7.961) (-1.574 2.388 7.987) (-1.197 2.479 7.638))! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/13/2001 03:01'! mimeEncodedTextureJPEG ^ '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCACQAHMDASIAAhEBAxEB/8QAHQAAAgIDAQEBAAAAAAAAAAAABQYHCAADBAIJAf/EAD8QAAECBAQDBQYEBAQHAAAAAAECAwAEBREGEiExBxNBIlFhcYEIFDKRofAJI7HBQlLR4QoVYvEWFyQzNFOS/8QAGwEAAgMBAQEAAAAAAAAAAAAAAwQCBQYBAAf/xAAyEQABAwMBBAgGAwEBAAAAAAABAAIDBBEhEgUxQVETFCJhcZHR8AYygaGxwRVT4TOC/9oADAMBAAIRAxEAPwBQpr7bd3C2vs6lV9PL1g3I1P32ZLbRTylCxukDW1oBBgrZytkhKkjQwWokv7m+0psAqa+IG2VW+8I9CHBbdtTY4XpWAvfqkyeyVFVyrKAPWJe4e4Kp9EShKcjroAzlZuCO63XWFrCqDNqSVMpaWpZIsonW9odZdxMgltZQtSiCFlIG/h4ecLlthZWUJYTqVkeAlRlaOrNMgICiFNpDmQJ13sOsWNwJiWgS5U41KOh1Aut7maknYZbiKV8Op2p1FOaVKgE2Sk5gAjUbg+FonTh7Ra5VUIbWhaFgglZcACteloTc4tcr6OOOaHQ64HMFW9wFjduqyfLcW0kIHZUp4fD9kQytVFp5wpS60ogXslYJt5RCGBuHlQkW0vOOcttQtckkEnbUaD6QeqWE6q1lcSFKSnRSU3zeBv8AKLBtW4NFwsNXbHpDUERygevmpPRWZVZsH2ye4KuY9moNJeCCoAlOa50FogWv1WsU6YCwh9KlDL2Uk5VfXXaA8xjKuy04G1Pz7ZT1La9AdxrpvA3bTAxZHi+EHSDUyQKyzbyHfgUlVu43j1EBYS4xVGVdZYemVcty4QypJTlHUk/doOYm9osU6VLbTDinEoKdF2UpV9wdYJ/JxBmtySl+E61soiYNV/fFSDjfiLIYKkFuOr5zw2aQbq9e6Ikq+IJ3Hqn3JlxMvzjnbAuQkAaAWhAxrxHerr8sZpz3ILPaZVYreF7XuDr/AG9IK4Qxw5h2WTyZoocKVWUUpWU3Fut7C2sZ2trDO4l+4bgthQfDPUYOkaLynnw8N/7QHEMrJU6svszdQpaZlBHMCldoEgGx031jIr1xKmJGfx3VHkVRshbxN1rUkk2Fza4sL7eEZGSdBM46gbX7ltWua0BpkyPfJUyolNSqmh9ZJUkJJFj2h8vswXdkEuTCUNBRsMoTew26/WBmF12aCC+4tCU5NLX+V4b6fTEyxRaxU6rN0zfWPrb/AAXxyO+AjmEZMussNoRy1JNrdB0uIkvBvDqerziULbLkre2ml9fK994GcH8Ny1QmGy+lCMnbWpSxYDe56RI2DfbBwxw7qTtIlWJWqziHCkKCyhpFtySB+49dor6mdrXWIyrujjaGh0jrBTbwG9l9NIcanJt2XTKugBaHFDmA+Ol+/v3i1+HabQcJUtlbSZZKRZJcCcwP9LRVDDntrYIpsi+ur16jSEsylOdKVKdWVG/wkADQbd9/CFau/iUYBxDPpk6HVXnEuKy5phCkhy972NraQvHXxjDW3KJX0vWiIzJpZ3fvvV4KwqQlHw+X2pdggLKkXsvbuHhBOlsyryUlLzUxftJAI0H7+sUTo3tEKr8n7sxMpdl31lSXM6rAHp5Q2VD2mnMM0Vu02U8hOZSs57VvD76wcVbW5LEjJ8Nh8YEc1z4cOCuW7TZd83XLsrP+pAMcVTwdTKulQfkmF5jckJsSe/SKOzH4wFM4fuplp1Qm0NjLnKc4GnVVwfl0iSeDn4q+BOMNWEhL1WQkZlxH5ZmU5ElX8p7f9N+kEdWwEdppP0VFJsmrgd2HjHIkKTcecAEtuuv0pwNqXdSi7sgdwMV64n0qrYafdLcy84ZcHsJVzMx3uAPSJEqH4lOH6BxAVhytU9DrbiSsTMk7nGQDXMk7ED/UbwM4x0GU4k4XexJgWttVBCmyosZgHWweljqD3eUZ6sMLmCanyPfArffD9bWQy9V2j4A788iRu+qrLjDiPUziVExNNrlZhtpICSTqOmn7RskeN080ObL3UV3BzgZnOmnntC67hx6UmVe9OTqqlMOnmJe7RNv0gRWJ80SabZVlKANioC5gbbYHvmryoc4k2uP8W3EmNE1quzU1NSbIfeXddpe47t/IRkKc5ilSJpwIWUpvoNNPrGRDqFOc6Pu71SX8jUjAd+PRRbSaW0h1ammlITomwsAm8FWJxMjNBK0ZhbQgW06b/esb5mhKCVLaUtK7WBGx8/8AeFvEE09JTAzj8sg6qGmkbLWDvWB7TQmHEfEJ6Spr7LbikNhBAAUQkp8xFROMvHucw81PTFNaWoyqVqcU0AtVhuRqB6kxKvEasVHF7aaZJoMuw+cjjyb5st9befzjv4Z4Rc4b4MrtGpiGlS2Jmg1UUPspeQ4EnMkgqBKVA9UkRGGnje4ulJAtwFyT5jHuyFLLJYNjye/AA7t+fd1QZ/2vcSYkrPuap2bkC65y7uhKwFX2UCLju30iyXBXiTVUU+WM7MpVN7hVgW3BvcH9o4ap+HfIIxpN1+anJ2ZdmHzMoRNPcy6yb5lG2ZWpvqYM4Q4WS/CdpxM7z35N13OGlnQm98wNrg+XhB4TFpDbZ4pUQ1TbvkKud7KfFlGKkN0948ubZKQEZtCTtbwhk/EE4iT/AAB4Su1JlPMmFJIQybkrOnUnSwMJn4U+Dqdj/wBqOkipMKTTFvJs0oXKk3Fr30F9Nf12ixH+IU4LTCcCUqep8qU0VKUpeQi5DRva47unhqPC1Pt9jomRvZuc4A91/f3Wp+H5tb3QSntFri3/AMi/+/RfKCn8V8S8XUB1E6hCnwVG4vk7730AEJ1Z9pSZ4K4u/wAqdemqnPNqBVmlUIBKtrElJN/CJA4McNKZidczI0ubfpa2nSuYYzkGY81DW3hpDx7QXsDHjJVW6tSHKdTXJ6XZYnw8gqQtLVilSAUkpVoLkKEWVOyIab4B9+SpK2OpIOjtOHr+bei28Evaip3EqTkHqgqoU6ZSrK3MB5WRBBsQsE3BGux0vFz/AGfOPtY4fVRTsy4mekZpkNBaVBRKbggg30HqLxUimeypROH3CJrDrM0++WX/AHlx1s3cdXe5sbWA8oa+DxxBg+k+4TEq5PU/mHkJKilxkedjp6dYWqmU7nuYw7vI33p+hdVRMY+YWP3HL7BXJ4iY2mKwkVCiJAedAzJWe1f+bKdO+IzxHMTOInUsvsJZfB/McJIv/XeODCTNfr6Uf+S1KoHwFBX6Xt0H6Q1qoy5APvzjaXEtAqU4tNsum33eKB0IjNlsI6yWpaOajCclXqfMrZVNKQUH4c219YyGOefkp6bW8lt1KVm4AJ/pGQPU8YLSuGli4lLsnVgJjkDV4WVdQuL9/wBPu8FZnCbOM2+WpKEkJtmCNfrCexUEy05YqUo21IIvfoIO0rGSpd1pSFjKpNgdRqe/pGufFqCx8LwPmSvibhe9RKkQFIU2LFKspsfpHqVoyUSpQ5dZWOlkW8O8w9zGKRWEWcyJdFwk2v6XgLO4WXPNLU6SlbaioaEeMBBeBpcmTTxuOpqTp6jls3yJS8SQkaqOgt96QrYi4aDEU40qeWVrC+y02ntKPjaJok+H/vaCVFbRyAlxVyB1PgNoUsfYmlqNU5ekUt9pVWmFjK8LAtanXUbeUcY46gBvXZYbR3O5WZ/DF9l+oIx3KVJpoMMh9CnTcDlgHS2/lFkfxf6hMTXCY0oyin5R9i61pF1Juq3y0EVQ9kD2mH+A9ckpF+tIfW48lLjhBAZJP1GvWLDe2Z7cGAK9gdNJqlRSuqzYVK5eXZIXa1wdupN4V2w0S0oYDxFu+1sK12VTFu0IJBbSwOB5tLgcr5W4M4bf8PY0M7KJKZpJyqQRYOp7iBuf6RO+DXnG3QkpmJYGxKEnNlPXfp5QmY0pLnDfEzM/UH2Z+hzjgDM+1qZYk6Bdul4m/C+DFVqXlnncq0KSnJMtkEKBG/je0L09S/ogDkDHh75eSsKvZjRMW7ic+Pel6RpDFZaUHUTC3QbDsjsk+HX5xIfDrguKm4yhBW4lRAB5fW4uP7wz4O4SqbTmLqVIUq5zJF/Pbv8AGDya9O8MWlLaflct7XVlN9NoGZhqwmmbMOgOfuRitcOBg2noZZm1trKRdJAsfDQxD3EOrS1FVMMTGSaDpJIuBa/QgX+xHbj/AI6rmlvKU/23E3KU6CxOltendeITxPiEVeoB33hxaVXVkJ3P2YSLHl2Uy+WFjNDN4R416XBPLbQlHQBBNoyEl6t5HVD3lDet8p3EZB7Dn+fRVeTm6AGspd5ZQQogAdwHf+kds2/zENjOBnOhG23384U5NhUnLucs5SbJVcXCtf1ghJ1VYnktrcUkJFwLDQ2jVGxGCsAHpqw9UFSkygurIsSCNwDEj0Wcl3aWHH1BSem9z9iIiZnWfe7IcSAQc2YW2hqp9XaTLgc8BBFtDZKTbUX7oG93ZJTUM1nAXW/jFxPmGKc5LSSOWtX5aQlOgB03+9ogyrys1RJkTbag9O3JzOfCSbjTy0iRMTYilZtxbpW2WUKytnMASb7jwhSqbrNYlyrMcwJyjS6rQtTR2JceKbqqjXYA4H5Ue4RqeKqNjtVan8SNzsi6CldMck0o5Kh8JQsanxBJuIVfakxrxG4z4mprWEHZdmYZGdxbyk2J/lSFAgDqTa8TBJ4QmZhpTvKzJCgQTawNrdPGDuEMNM4fQ87lBWr4lcsXUrziVQ0HTY/LlDpHuOoOJs7efRIGFG8a1/AcrhqszDExOrSkz77bYbaQQRoLb3ttFxeCeNBK4WkZAFshhlKAUoG4SPkYr+3WWmZhfJWpd1XIVpa/jDDhjiKmnzyWETCUkkbEdPP0hIm98fMblaES6WhweSWiwvnCtIzxB/y+kWCyFbKNrBRJ3hA4kYwcrWZYKiwk3yBwHNb78YVjjhFbpSkJeC3m98pt4C3UwkV/iG5JKDCRmcXpcbXEIPis/vTp2rdliUZWpc6644/mShRuEg3CfWF6vvopzy0B/MsD+HY38I8SdcLcopayHLi+Un6xwtpdqjhWothSTmCBoCLXgpBVaaq4whTk0pa1Ei5J3ymMjJyWHvTmaayqvqAqwEZENff+VDpHc1zS89lKkqURoBfNr5x59/zz45ZuQnvtfSEmkYmXOTJzuAXAAKrgk6bw304NqeS4chWB/NY38rxoyeax5FzYI1TkKScyT2jdOuhEba5OLYwzOOpIA5eVISSDc+W39oHJnHEuDIQpX+k7CN8w8JmlrazmywbG4uLQGQ9kgI0Ng4KIuLGNqussSlGkVzk42jKApSktp87A/SE1HHbFOFnW0TuGRlYJzLQ/mCz32UBp6RYPB1LZlXXfeeWSsk5iLk29YMVDCdJmEhSGkFdrkEA3uY8x7W5PHKOYy7cbWUL0b2wZ6XkAuaoT6JRKtPygTfrtr1gvM+29IONFuXos++v4TZpStdjYZTaGiv0ulSSSl2QbUU/BdCSFHytAqlOSDUyErp0m0m10lLSQFa6R57o3cE9B0jW/OPJRpW/ajmqu88ZLClRcLZJIBykkE9CAfSNGEsV8ScZV6Xm5HDHJkULzOJcf/Mt5W/r1ieZHDrM6hsplmxzL3ygDT09IaMOMt4dSn3dtG9iBa4v1hMSMa6+lOPpjI23SfpDcEys3OssrKXZd4EJWgn4T1HTSNWJmxL1flIzEE2EMtDq7zD7yn22rkmxG9toRKnUxWMWu2UrkoVYKzE698Al7bwGiygR0bHNcb/tHBKoYCiVFWcDQqsiNFbxE3R2VltwFFrDKdvS+0C8X4nlaFIBClAGwtf8AiERJjLi8ucKghQSNiQnviOnVgKHSiMXKcpzHCFTSyrMok72OvyjIhWYx+svKzPG8ZHegS/XEwMVt9iYGdtSLaE9/rDthfGjU1lbWAbEkkqso2ER3MTKFOWUogAix+/O/rHO6AXypuYLROtr7mLYPNlRuJBuFPFPrLCnmyMybkEZQNYYJidlW22ykNnNrcDcmK5U/HU5SFZirmWPxXOn35QxUbiqKifzXFpCNSDqm0d034rwqA3ep7lqSmfmQhlaEhOxSRr4QXlqK23mLoJvpmTsDEJSHEoS80lxt4EAAmx1T6eUNKeP8nyEhaygq0zkCyrGImLCfhqQXZUjyWHaetxQnS2A0m5Kki36Xjjawdh5/8wMjOFdmwSCrx2iMk8ZGUzClNzbakLOU5lC4HfaOqncTaeytS0TRUSdAem/7wN45K0hqWAcFJl5SnzoQhILSkai1sp6RyTZMs4VJcCUrUTe4JH94SjjqUemUzK5kFdiMtwNO77vCxxA4raAS6gnlkg3Vp526wg9hBTbqqPThPdbrAS040lwns5iQodk9/nCs/jVnDEtzXlspOqhff1iHcZ8fJWiSys8wtTm9kkWPziFce+0NM4nmS2wvKi2Q6kk+Nj+0SZE4qpnr2jepk4rcemJ6ccS0UqUL2KdSIiCtcRX6g+puVzl5Y7ThN7+WsJiqm7UFDO6talHpuPKH3hlhBtb7S1oSoki2YEnv0EPQUzndlov+1VTV7ndo4Q9jDs9MtJcUmbUpYuTbeMicWMMFLCAGMoyiwU5lO3d0jItBsmp/rKq/5Wl/tCWJjE7S27tuBSraWO3hHBM4kddUklKU22tuYhuSo0tKP55Ssz8sB/CpwlPl32gtT6/Vqc52ahIzydLJWcltDfe5/wB4YdsqUZ3pBu2oiLHCk1irTLz47CgFHUdAPOPc9Rai8xzWEqRfYgbmAFB4u+5cvnUs66KLTiVjzFiNPSGiV9oSnIlXG3pGaQlN1J7BVffTQHX6a7wu/Z0oGAUwzaELt7ggYqeIpNzKlHPKOqiDmt5xqqOJa0pGYyjg/hulV9fOGNjjnhx5ZSpuYQpQsAqXUkDXYnprGlHG/DLJuOcVdP8Ap17/ACgRpZuIz4JgVMHBw80ozWNqjTEkutTKeqAAo5u6PTPFKdlsxCZuwBBCUqAHkLQcnOJeHqxMhxcu8vKRYiVWbn5R+zeNMOuIUlumzKr9S2hIH/0RHm0k5GGnyK8aunB/6DzCW5jj1UJNJQBM2N/jQvT5CFDE3HmpTa1plW3nEnW6iQb9D3w5Ts/I1N1akSDDCRrdx5HW/wDLeAU/L0KWdKpiZl2wo9oNtqWSN7AkCJt2bO7Jbb62QZNqQMwH38ASovqeIKzXF2fcVkV/DfSCmEME1KvzQTLS77oUbKUB2R4lWw+cNbdZoIJEjTpyrP33Wk5QetkptpDLKSFfq8mnnzLVIkrf9ppGVVu61tIs6bYvF58vU+iqajbQGGDPf6D/ABecOYMo+FUJXVp5D8za/Il+0UHxVr9PrB//AJs/5U0WKNKiWQE2DoFlnTqdSYVKgqmUAHMszTotdxar38YGyc3OYonOTT5da0K0ukaC/jFxDGGDo4Rnu9VSTTSTdqU4793kj0zjmpOzC1LnnQonUZzpGQUk+A087LIU6tQcULq7UZDfU5+Q8ylOsRqMClVwlWa/cBHv3a1rOKSdbQaVKMTBN0nvvHPN0AZhy1mwUdwNN4ULSEyHDchaqS6pZyTDlxpYmPMzSZ+xyTTlt/iy9I6jTJpDhygkA72jU49MSyCVBQsbG8czfKkCVzCl1hRNplxR3tzDb9Y9M0asuKt724Tpa6vTvjtYqq0OG4USO/XwghJV1LK+0gkJ010vHWtbzXi48kPl8I1p0396mL31ubX+sd8pwrrE8e3NupVa+rmnpBqSxalhPwkaW3H33R0PcRUS2ckqve/TeDBsQ+ZD1ycFopnAguvIM5UXgCP/AHXv9ILs8M8K4fWFuI96cR/E45p5wrT/ABRmXiUtqcOthlGv7xwIlK7iuYs2h9CVakq008o62UbomXK4WPOXusm+qcR5OhSimZBthpNtkmFNzFFZxhMhEsh9dzpa5FoZcM8EASJmoPqeUNchFwPnEgUaWkMMsoSwhpKwLgiwt/SCtge/MzrdyEZWtxGLpHwZwCm6lMpmaqsBKrEtG/8AbpEu4eoFOwiwhDDTLKECxKQAT+8ApvGpVohRNjvtb70jlViF6cXdtSxYeH33Q7G9kbbRhKyB7zd5Tq9iqXQ6RqbdcsZCG488pZIdXrr3Rkc1yLnRMX//2Q=='! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/13/2001 20:29'! texture ^ (JPEGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: self mimeEncodedTextureJPEG readStream)) nextImage asTexture flipVertically interpolate: true; wrap: true! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 9/23/1999 02:45'! texture2 | r1 answer | Utilities informUser: 'Choose a rectangle with interesting stuff' during: [r1 _ Rectangle originFromUser: 128@128. Sensor waitNoButton]. answer _ (B3DTexture fromDisplay: r1) asFormOfDepth: 32. answer _ answer asTexture. answer wrap: true; interpolate: true; envMode: 0. ^ answer! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 9/23/1999 03:02'! texture3 | answer | answer _ (self texture asFormOfDepth: 16) asFormOfDepth: 8. answer _ answer asTexture. answer wrap: true; interpolate: true; envMode: 0. ^ answer! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/25/2001 18:14'! texture4 ^ (ImageReadWriter formFromFileNamed: 'face/katia3.png') asTexture flipVertically interpolate: true; wrap: true! ! !AvatarBuilder methodsFor: 'private-face' stamp: 'len 1/29/2001 12:23'! textureCoordinates | minX maxX minY maxY tex x y vertex | minX _ minY _ 1000000.0. maxX _ maxY _ -1000000.0. vertices do: [ :each | minX _ minX min: each x. minY _ minY min: each y. maxX _ maxX max: each x. maxY _ maxY max: each y]. tex _ B3DTexture2Array new: vertices size. 1 to: vertices size do: [ :index | vertex _ vertices at: index. x _ vertex x - minX / (maxX - minX). y _ vertex y - minY / (maxY - minY). tex at: index put: x @ y]. ^ tex! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/24/2001 16:54'! eyeballFaces | faceList vtx m1 m2 baseDir vtxList dir lastVtx nextVtx face verticalSteps latitudeSteps latitudeVertices | verticalSteps _ 12. latitudeSteps _ 6. faceList _ WriteStream on: (Array new: verticalSteps * latitudeSteps). "<--- vertex construction --->" m1 _ (B3DRotation angle: 360.0 / verticalSteps axis: 0@-1@0) asMatrix4x4. m2 _ (B3DRotation angle: 90.0 / latitudeSteps axis: 0@0@-1) asMatrix4x4. baseDir _ 0@1@0. vtxList _ Array new: verticalSteps + 1. 0 to: verticalSteps do:[:i| i = verticalSteps ifTrue:[baseDir _ 0@-1@0]. "Make closed for sure" latitudeVertices _ Array new: latitudeSteps + 1. vtxList at: i+1 put: latitudeVertices. dir _ baseDir. 0 to: latitudeSteps do:[:j| vtx _ B3DSimpleMeshVertex new. vtx position: dir * self eyeballRadius; normal: dir. vtx texCoord: (dir x + 1 / 2.0) @ (dir y + 1 / 2.0). latitudeVertices at: j+1 put: vtx. dir _ (m1 localPointToGlobal: dir) normalized. ]. baseDir _ (m2 localPointToGlobal: baseDir) normalized. ]. "<--- face construction --->" "Construct first round separately as triangles" lastVtx _ vtxList at: 1. nextVtx _ vtxList at: 2. 1 to: latitudeSteps do:[:i| face _ B3DSimpleMeshFace new: 3. face at: 1 put: (lastVtx at: i). face at: 2 put: (nextVtx at: i+1). face at: 3 put: (nextVtx at: i). faceList nextPut: face]. "Construct the next rounds as quads" 2 to: verticalSteps do:[:i| lastVtx _ vtxList at: i. nextVtx _ vtxList at: i+1. 1 to: latitudeSteps do:[:j| face _ B3DSimpleMeshFace new: 4. face at: 1 put: (lastVtx at: j). face at: 2 put: (lastVtx at: j+1). face at: 3 put: (nextVtx at: j+1). face at: 4 put: (nextVtx at: j). faceList nextPut: face]]. ^faceList contents! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/15/2001 20:45'! eyeballMesh ^ (B3DSimpleMesh withAll: self eyeballFaces) asIndexedMesh! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/15/2001 20:44'! eyeballRadius ^ 1.35! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/29/2001 12:39'! eyeballTexture ^ eyeballTexture ifNil: [eyeballTexture _ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: self mimeEncodedEyeballTexturePNG readStream)) nextImage asTexture interpolate: true; wrap: true]! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/24/2001 09:45'! leftEyeballCenter | right | right _ self rightEyeballCenter. ^ right copy x: right x negated! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/29/2001 12:34'! leftEyeballMesh ^ leftEyeballMesh ifNil: [leftEyeballMesh _ self eyeballMesh translateBy: self leftEyeballCenter]! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/15/2001 20:47'! mimeEncodedEyeballTexturePNG ^ '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'! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/24/2001 09:50'! rightEyeballCenter ^ 2.0@2.8@6.33! ! !AvatarBuilder methodsFor: 'private-eyes' stamp: 'len 1/29/2001 12:34'! rightEyeballMesh ^ rightEyeballMesh ifNil: [rightEyeballMesh _ self eyeballMesh translateBy: self rightEyeballCenter]! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:37'! faceObject ^ B3DSceneObject new geometry: self faceMesh; texture: self texture; material: self material! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:38'! leftEyeballObject ^ B3DSceneObject new geometry: self leftEyeballMesh; texture: self eyeballTexture; material: self material! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:58'! light ^ B3DPositionalLight new lightColor: self lightColor; position: self lightPosition; attenuation: (B3DLightAttenuation constant: 1.0 linear: 0.0 squared: 0.0); yourself! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 9/23/1999 01:59'! lightColor ^ B3DMaterialColor new ambientPart: (B3DColor4 r: 0.0 g: 0.0 b: 0.0 a: 1.0); diffusePart: (B3DColor4 r: 0.5 g: 0.5 b: 0.5 a: 1.0); specularPart: (B3DColor4 r: 0.8 g: 0.8 b: 0.8 a: 0.8); yourself! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:59'! lightPosition ^ B3DVector3 x: 0 y: 0 z: 30! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 21:00'! material ^ B3DMaterial new specularPart: Color white; ambientPart: Color white; diffusePart: Color white; emission: Color white; shininess: 20.0; yourself! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:41'! material2 ^ B3DMaterial new specularPart: (B3DColor4 r: 0.9 g: 0.9 b: 0.9 a: 0.9); ambientPart: (B3DColor4 r: 0.9 g: 0.9 b: 0.9 a: 0.9); emission: (B3DColor4 r: 0.5 g: 0.5 b: 0.5 a: 1.0); shininess: 20.0; yourself! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 8/10/2001 20:38'! rightEyeballObject ^ B3DSceneObject new geometry: self rightEyeballMesh; texture: self eyeballTexture; material: self material! ! !AvatarBuilder methodsFor: 'scene' stamp: 'len 1/29/2001 12:37'! scene | answer camera | answer _ B3DScene new. answer objects add: self faceObject; add: self leftEyeballObject; add: self rightEyeballObject. camera _ B3DCamera new. camera position: 0@0@30. camera fov: 15. answer defaultCamera: camera. answer lights add: (B3DAmbientLight color: Color white). answer lights add: self light. ^ answer! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 1/29/2001 12:17'! avatar avatar ifNil: [self buildAvatar]. ^ avatar! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 1/29/2001 12:17'! buildAvatar avatar _ Avatar new. self buildJaw; buildLeftEye; buildRightEye; buildMuscles! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 1/29/2001 12:18'! buildJaw avatar jaw: (Jaw new mesh: self faceMesh; indices: (1 to: 59), (257 to: 256 + 58))! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 2/9/2001 10:45'! buildLeftEye avatar leftEye: (Eye new mesh: self leftEyeballMesh; center: self leftEyeballCenter; upperEyelid: (Eyelid upper mesh: self faceMesh; indices: (245 to: 251)); lowerEyelid: (Eyelid lower mesh: self faceMesh; indices: (251 to: 256)))! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 1/29/2001 12:20'! buildMuscles | muscles | muscles _ Dictionary new. self muscles do: [ :each | muscles at: each name put: each]. avatar muscles: muscles! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 2/9/2001 10:46'! buildRightEye avatar rightEye: (Eye new mesh: self rightEyeballMesh; center: self rightEyeballCenter; upperEyelid: (Eyelid upper mesh: self faceMesh; indices: (256+245 to: 256+251)); lowerEyelid: (Eyelid lower mesh: self faceMesh; indices: (256+251 to: 256+256)))! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 1/30/2001 17:08'! muscles ^ #(leftAngularDepressor leftFrontalisInner leftFrontalisMajor leftFrontalisOuter leftInnerLabiNasi leftLabiNasi leftLateralCorigator leftSecondaryFrontalis leftZygomaticMajor rightAngularDepressor rightFrontalisInner rightFrontalisMajor rightFrontalisOuter rightInnerLabiNasi rightLabiNasi rightLateralCorigator rightSecondaryFrontalis rightZygomaticMajor) collect: [ :each | (Muscle perform: each) mesh: self faceMesh]! ! !AvatarBuilder methodsFor: 'building' stamp: 'len 2/9/2001 11:29'! openInWorld " AvatarBuilder new openInWorld " | answer controlMorph sceneMorph | answer _ self avatar. controlMorph _ AvatarControlMorph new avatar: answer. controlMorph scene: (sceneMorph _ B3DSceneExplorerMorph new scene: self scene; switchRotationStatus). controlMorph openInWorld. sceneMorph openInWorld. ^ answer! ! !AvatarBuilder class methodsFor: 'instance creation' stamp: 'len 1/13/2001 04:03'! new ^ super new initialize! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 2/9/2001 11:39'! avatar: anAvatar | slider | avatar _ anAvatar. anAvatar muscles keys asSortedCollection do: [ :each | slider _ self newSliderForMuscle: (anAvatar muscles at: each). ((each beginsWith: 'Left') ifTrue: [left] ifFalse: [right]) addMorphBack: slider]. left addMorph: (self newSliderFor: anAvatar leftEye upperEyelid setter: #angle: getter: #angle max: 5.0). left addMorph: (self newSliderFor: anAvatar leftEye lowerEyelid setter: #angle: getter: #angle max: 5.0). left addMorph: (self newSliderFor: anAvatar leftEye setter: #rotationY: getter: #rotationY min: -16.0 max: 16.0). left addMorph: (self newSliderFor: anAvatar leftEye setter: #rotationX: getter: #rotationX min: -30.0 max: 30.0). right addMorph: (self newSliderFor: anAvatar rightEye upperEyelid setter: #angle: getter: #angle max: 5.0). right addMorph: (self newSliderFor: anAvatar rightEye lowerEyelid setter: #angle: getter: #angle max: 5.0). right addMorph: (self newSliderFor: anAvatar rightEye setter: #rotationY: getter: #rotationY min: -16.0 max: 16.0). right addMorph: (self newSliderFor: anAvatar rightEye setter: #rotationX: getter: #rotationX min: -30.0 max: 30.0). self addMorphBack: (self newSliderForJaw: anAvatar jaw)! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 12/21/2001 14:33'! initialize | sliders | super initialize. self layoutInset: 0. self color: (Color r: 0.452 g: 0.452 b: 0.645). self listDirection: #topToBottom; hResizing: #shrinkWrap; vResizing: #shrinkWrap. left _ AlignmentMorph newColumn color: self color. right _ AlignmentMorph newColumn color: self color. sliders _ AlignmentMorph newRow. sliders addMorph: left; addMorph: right. self addMorph: sliders. self addMorph: (SimpleButtonMorph new target: self; borderColor: Color black; label: 'play expression...'; actWhen: #buttonDown; actionSelector: #playExpression)! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 12/21/2001 14:28'! newSlider | r | r _ AlignmentMorph newColumn. r color: self color; borderWidth: 0; layoutInset: 0. r hResizing: #spaceFill; vResizing: #rigid; extent: 5@20; wrapCentering: #center; cellPositioning: #topCenter. ^ r! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 2/9/2001 11:40'! newSliderFor: anObject setter: setter getter: getter max: max ^ self newSliderFor: anObject setter: setter getter: getter min: 0 max: max! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 12/21/2001 14:30'! newSliderFor: anObject setter: setter getter: getter min: min max: max | r slider m | r _ self newSlider. m _ UpdatingStringMorph new target: anObject; getSelector: #yourself; width: 200; step. r addMorphBack: m. slider _ UpdatingSimpleSliderMorph new color: (Color r: 0.839 g: 0.548 b: 0.355); extent: 200@2; target: anObject; actionSelector: setter; getValueSelector: getter; minVal: min; maxVal: max; adjustToValue: (anObject perform: getter). r addMorphBack: slider. ^ r! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 12/21/2001 14:30'! newSliderForJaw: aJaw | r slider m | r _ self newSlider. m _ UpdatingStringMorph new target: aJaw; getSelector: #yourself; width: 400; step. r addMorphBack: m. slider _ UpdatingSimpleSliderMorph new color: (Color r: 0.839 g: 0.548 b: 0.355); extent: 400@2; target: aJaw; actionSelector: #angle:; getValueSelector: #angle; maxVal: 10; adjustToValue: aJaw angle. r addMorphBack: slider. ^ r! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 12/21/2001 14:31'! newSliderForMuscle: aMuscle | r slider m | r _ self newSlider. m _ UpdatingStringMorph new target: aMuscle; getSelector: #yourself; width: 200; step. r addMorphBack: m. slider _ UpdatingSimpleSliderMorph new color: (Color r: 0.839 g: 0.548 b: 0.355); extent: 200@2; target: aMuscle; actionSelector: #contraction:; getValueSelector: #contraction; maxVal: aMuscle clamp; adjustToValue: aMuscle contraction. r addMorphBack: slider. ^ r! ! !AvatarControlMorph methodsFor: 'initialization' stamp: 'len 2/9/2001 11:26'! scene: aMorph scene _ aMorph! ! !AvatarControlMorph methodsFor: 'accessing' stamp: 'len 1/29/2001 11:54'! avatar ^ avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:55'! playAngerExpression Viseme anger playOn: avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:57'! playDisgustExpression Viseme disgust playOn: avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 9/28/1999 01:51'! playExpression "Invoke a menu of playing an expression." | aMenu | aMenu _ CustomMenu new. aMenu addList: #( ('neutral' playNeutralExpression) ('anger' playAngerExpression) ('digust' playDisgustExpression) ('fear' playFearExpression) ('happiness' playHappinessExpression) ('sadness' playSadnessExpression) ('surprise' playSurpriseExpression)). aMenu invokeOn: self defaultSelection: nil! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:58'! playFearExpression Viseme fear playOn: avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:58'! playHappinessExpression Viseme happiness playOn: avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:58'! playNeutralExpression avatar relax! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 1/29/2001 11:58'! playSadnessExpression Viseme sadness playOn: avatar! ! !AvatarControlMorph methodsFor: 'menu' stamp: 'len 2/9/2001 11:41'! playSurpriseExpression Viseme surprise playOn: avatar! ! !AvatarControlMorph methodsFor: 'stepping and presenter' stamp: 'len 2/9/2001 11:37'! step self flag: #hack. scene changed! ! !AvatarControlMorph methodsFor: 'stepping and presenter' stamp: 'len 2/9/2001 11:34'! stepTime ^ 0! ! !Eye methodsFor: 'initialization' stamp: 'len 2/9/2001 11:00'! initialize rotation _ 0@0! ! !Eye methodsFor: 'accessing' stamp: 'len 2/1/2001 22:54'! center: aVector3 center _ aVector3! ! !Eye methodsFor: 'accessing' stamp: 'len 2/28/2000 23:53'! lowerEyelid ^ lowerEyelid! ! !Eye methodsFor: 'accessing' stamp: 'len 1/29/2001 12:03'! lowerEyelid: anEyelid lowerEyelid _ anEyelid! ! !Eye methodsFor: 'accessing' stamp: 'len 1/29/2001 12:01'! mesh: aB3DIndexedMesh mesh _ aB3DIndexedMesh! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 11:11'! rotate: anglePoint | xform | rotation _ rotation + anglePoint. xform _ B3DMatrix4x4 withOffset: center negated. xform _ xform composedWithGlobal: (B3DRotation angle: anglePoint x negated axis: 0@1@0) asMatrix4x4. xform _ xform composedWithGlobal: (B3DRotation angle: anglePoint y axis: 1@0@0) asMatrix4x4. xform _ xform composedWithGlobal: (B3DMatrix4x4 withOffset: center). mesh transformBy: xform! ! !Eye methodsFor: 'accessing' stamp: 'len 2/1/2001 18:29'! rotation ^ rotation! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 11:03'! rotation: aPoint self rotate: aPoint - rotation! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 10:59'! rotationX ^ self rotation x! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 10:59'! rotationX: angle self rotation: angle @ self rotation y! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 10:59'! rotationY ^ self rotation y! ! !Eye methodsFor: 'accessing' stamp: 'len 2/9/2001 10:59'! rotationY: angle self rotation: self rotation x @ angle! ! !Eye methodsFor: 'accessing' stamp: 'len 2/28/2000 23:53'! upperEyelid ^ upperEyelid! ! !Eye methodsFor: 'accessing' stamp: 'len 1/29/2001 12:04'! upperEyelid: anEyelid upperEyelid _ anEyelid! ! !Eye class methodsFor: 'instance creation' stamp: 'len 2/9/2001 11:00'! new ^ super new initialize! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 1/29/2001 12:03'! activateWith: value | radians cos sin vertices vertex y z | radians _ (value * direction) degreesToRadians. cos _ radians cos. sin _ radians sin. vertices _ mesh vertices. self indices do: [ :each | vertex _ vertices at: each. y _ vertex y. z _ vertex z. vertex y: cos * y - (sin * z). vertex z: sin * y + (cos * z). vertices at: each put: vertex]. self triggerEvent: #activated! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:59'! angle ^ angle! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:58'! angle: aNumber self activateWith: aNumber - self angle. angle _ aNumber! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:57'! direction ^ direction! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:57'! direction: oneOrMinusOne direction _ oneOrMinusOne! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:55'! indices ^ indices! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:55'! indices: aCollection indices _ aCollection! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 2/28/2000 23:57'! initialize angle _ 0! ! !Eyelid methodsFor: 'as yet unclassified' stamp: 'len 1/29/2001 12:04'! mesh: aB3DIndexedMesh mesh _ aB3DIndexedMesh! ! !Eyelid class methodsFor: 'instance creation' stamp: 'len 2/29/2000 00:26'! lower ^ self new direction: -1! ! !Eyelid class methodsFor: 'instance creation' stamp: 'len 2/28/2000 23:56'! new ^ super new initialize! ! !Eyelid class methodsFor: 'instance creation' stamp: 'len 2/29/2000 00:26'! upper ^ self new direction: 1! ! !Head3DMorph methodsFor: 'initialization' stamp: 'len 2/17/2000 07:55'! initialize super initialize. self extent: 140 @ 100. self color: Color red. queue _ SharedQueue new! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 2/28/2000 00:45'! articulate: aPhoneme aPhoneme isVowel ifTrue: [self head jaw angle: 2.5] ifFalse: [self head jaw angle: 0]. self changed! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 2/28/2000 00:45'! head ^ head! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 2/28/2000 00:45'! head: aHead head _ aHead! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 2/17/2000 07:55'! playEvent: event at: time self queue nextPut: time -> event! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 2/17/2000 07:56'! queue ^ queue! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 9/23/1999 02:21'! scene ^ scene! ! !Head3DMorph methodsFor: 'accessing' stamp: 'len 9/23/1999 02:21'! scene: aB3DScene scene _ aB3DScene! ! !Head3DMorph methodsFor: 'drawing' stamp: 'len 9/26/1999 17:55'! drawOn: aCanvas aCanvas asBalloonCanvas render: self. aCanvas frameRectangle: self bounds color: self color! ! !Head3DMorph methodsFor: 'drawing' stamp: 'len 2/17/2000 01:13'! pickVertexAt: aPoint | aRenderer answer | aRenderer _ (B3DRenderEngine defaultForPlatformOn: nil) new. aRenderer viewport: (self bounds insetBy: 1@1). aRenderer clearDepthBuffer. aRenderer loadIdentity. aRenderer _ aRenderer asPickerAt: aPoint. self scene renderOn: aRenderer. self halt. aRenderer finish. answer _ aRenderer topMostVertex. aRenderer destroy. ^ answer! ! !Head3DMorph methodsFor: 'drawing' stamp: 'len 9/23/1999 02:22'! renderOn: aRenderer aRenderer viewport: (self bounds insetBy: 1@1). aRenderer clearDepthBuffer. aRenderer loadIdentity. self scene renderOn: aRenderer! ! !Head3DMorph methodsFor: 'menus' stamp: 'len 2/16/2000 23:37'! addCustomMenuItems: aCustomMenu hand: aHandMorph "Add morph-specific items to the given menu which was invoked by the given hand." super addCustomMenuItems: aCustomMenu hand: aHandMorph. aCustomMenu add: 'open muscle controls' action: #openMuscleControls! ! !Head3DMorph methodsFor: 'menus' stamp: 'len 1/13/2001 00:55'! openMuscleControls self head openControlMorph! ! !Head3DMorph methodsFor: 'stepping and presenter' stamp: 'len 2/17/2000 07:56'! step | now | super step. now _ Time millisecondClockValue. [queue isEmpty not and: [now >= queue peek key]] whileTrue: [queue next value actOn: self]. " self face lips updateShape"! ! !Head3DMorph class methodsFor: 'examples' stamp: 'len 1/29/2001 11:36'! example | builder | builder _ AvatarBuilder example. ^ self new scene: builder scene; head: builder face! ! !Jaw methodsFor: 'initialization' stamp: 'len 9/11/1999 03:43'! initialize angle _ 0.0! ! !Jaw methodsFor: 'accessing' stamp: 'len 9/11/1999 03:35'! angle ^ angle! ! !Jaw methodsFor: 'accessing' stamp: 'len 2/17/2000 07:12'! angle: aNumber self activateWith: aNumber - self angle. angle _ aNumber! ! !Jaw methodsFor: 'accessing' stamp: 'len 9/11/1999 03:40'! indices ^ indices! ! !Jaw methodsFor: 'accessing' stamp: 'len 9/11/1999 03:40'! indices: aCollection indices _ aCollection! ! !Jaw methodsFor: 'accessing' stamp: 'len 1/29/2001 12:06'! mesh: aB3DIndexedMesh mesh _ aB3DIndexedMesh! ! !Jaw methodsFor: 'accessing' stamp: 'len 9/20/1999 01:17'! rotate: aNumber self angle: self angle + aNumber! ! !Jaw methodsFor: 'activation' stamp: 'len 2/17/2000 07:12'! activate self activateWith: self angle! ! !Jaw methodsFor: 'activation' stamp: 'len 1/29/2001 12:05'! activateWith: value | radians cos sin vertices vertex y z | radians _ value * Float pi / 180.0. cos _ radians cos. sin _ radians sin. vertices _ mesh vertices. self indices do: [ :each | vertex _ vertices at: each. y _ vertex y. z _ vertex z. vertex y: cos * y - (sin * z). vertex z: sin * y + (cos * z). vertices at: each put: vertex]. self triggerEvent: #activated! ! !Jaw methodsFor: 'activation' stamp: 'len 9/11/1999 03:35'! relax self angle: 0.0! ! !Jaw class methodsFor: 'instance creation' stamp: 'len 9/11/1999 03:43'! new ^ super new initialize! ! !Muscle methodsFor: 'initialization' stamp: 'len 9/20/1999 01:21'! initialize contraction _ 0.0! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/26/1999 18:08'! clamp: aNumber clamp _ aNumber! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 01:53'! end: aFloat end _ aFloat! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 02:12'! head: aB3DVector3 head _ aB3DVector3! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 01:43'! name: aString name _ aString! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 01:53'! start: aFloat start _ aFloat! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 01:46'! tail: aB3DVector3 tail _ aB3DVector3! ! !Muscle methodsFor: 'accessing-private' stamp: 'len 9/9/1999 01:54'! zone: aFloat zone _ aFloat! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/26/1999 18:07'! clamp ^ clamp! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/20/1999 01:19'! contract: aNumber self contraction: self contraction + aNumber! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:53'! contraction ^ contraction! ! !Muscle methodsFor: 'accessing' stamp: 'len 2/17/2000 07:11'! contraction: aNumber self activateWith: aNumber - self contraction. contraction _ aNumber! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:53'! end ^ end! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:44'! head "Answer the head of the muscle vector." ^ head! ! !Muscle methodsFor: 'accessing' stamp: 'len 1/29/2001 12:09'! length "Answer the distance from the head to the tail." ^ (tail - head) length! ! !Muscle methodsFor: 'accessing' stamp: 'len 1/29/2001 11:30'! mesh: aB3DIndexedMesh mesh _ aB3DIndexedMesh! ! !Muscle methodsFor: 'accessing' stamp: 'len 1/29/2001 11:30'! name ^ name! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:53'! start ^ start! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:44'! tail "Answer the tail of the muscle vector." ^ tail! ! !Muscle methodsFor: 'accessing' stamp: 'len 9/9/1999 01:47'! zone "Answer the zone of influence of the receiver." ^ zone! ! !Muscle methodsFor: 'activation' stamp: 'len 2/17/2000 07:09'! activate self activateWith: self contraction! ! !Muscle methodsFor: 'activation' stamp: 'len 1/29/2001 11:31'! activateWith: val | index direction vertices | indices ifNil: [self computeIndicesAndDirections]. vertices _ mesh vertices. 1 to: indices size do: [ :each | index _ indices at: each. direction _ directions at: each. vertices at: index put: (vertices at: index) + (direction * val)]! ! !Muscle methodsFor: 'activation' stamp: 'len 1/29/2001 12:09'! computeIndicesAndDirections | thet vertex vblen cosa cosv newv newp total proportion convertion vb va neutralVertices | neutralVertices _ mesh vertices. convertion _ 180 / Float pi. thet _ (zone / convertion) cos. total _ end - start. self length > 0 ifFalse: [^ self]. va _ self normalizedDirection. indices _ OrderedCollection new. directions _ OrderedCollection new. 1 to: neutralVertices size do: [ :each | vertex _ neutralVertices at: each. "Find the length of muscle head to the mesh node." vb _ vertex - head. vblen _ vb length. vblen > 0.0 ifTrue: [cosa _ (vb dot: va) / vblen. cosa > thet ifTrue: [vblen <= end ifTrue: [cosv _ 1.0 - (cosa / thet). vblen >= start ifTrue: [proportion _ vblen - start / total. newv _ (proportion * 90 / convertion) cos. newp _ vb * cosv * newv] ifFalse: [newp _ vb * cosv]. indices add: each. directions add: newp]]]]. indices _ indices asArray. directions _ directions asArray! ! !Muscle methodsFor: 'activation' stamp: 'len 1/29/2001 12:09'! normalizedDirection ^ (tail - head) safelyNormalized! ! !Muscle methodsFor: 'activation' stamp: 'len 9/10/1999 03:29'! relax self contraction: 0.0! ! !Muscle methodsFor: 'printing' stamp: 'len 9/26/1999 18:47'! printOn: aStream aStream nextPutAll: self name; nextPutAll: ' ('; print: (self contraction roundTo: 0.01); nextPut: $)! ! !Muscle class methodsFor: 'instance creation' stamp: 'len 9/26/1999 18:07'! fromArray: anArray | head tail | head _ anArray at: 3. tail _ anArray at: 2. ^ self new name: (anArray at: 1); head: (B3DVector3 x: head first y: head second z: head third); tail: (B3DVector3 x: tail first y: tail second z: tail third); start: (anArray at: 4); end: (anArray at: 5); zone: (anArray at: 6); clamp: (anArray at: 7)! ! !Muscle class methodsFor: 'instance creation' stamp: 'len 9/20/1999 01:21'! new ^ super new initialize! ! !Muscle class methodsFor: 'examples' stamp: 'len 2/27/2000 21:50'! exampleMuscles ^ #(leftAngularDepressor leftFrontalisInner leftFrontalisMajor leftFrontalisOuter leftInnerLabiNasi leftLabiNasi leftLateralCorigator leftSecondaryFrontalis leftZygomaticMajor rightAngularDepressor rightFrontalisInner rightFrontalisMajor rightFrontalisOuter rightInnerLabiNasi rightLabiNasi rightLateralCorigator rightSecondaryFrontalis rightZygomaticMajor) collect: [ :each | self perform: each]! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:04'! leftAngularDepressor ^ self fromArray: #(LeftAngularDepressor (-1.5700 -2.2210 8.0250) (-2.5590 -4.2770 5.3510) 0.3 4.5 65.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:04'! leftFrontalisInner ^ self fromArray: #(LeftFrontalisInner (-0.4870 3.6390 8.1010) (-0.3540 6.2470 7.2290) 0.1 3.6 35.0 4.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:04'! leftFrontalisMajor ^ self fromArray: #(LeftFrontalisMajor (-2.3810 3.8300 8.0000) (-2.2440 6.3630 6.9690) 0.1 3.7 65.0 0.5)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftFrontalisOuter ^ self fromArray: #(LeftFrontalisOuter (-3.0950 3.9700 7.8950) (-3.6390 5.6480 5.9450) 0.1 3.5 45.0 2.5)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftInnerLabiNasi ^ self fromArray: #(LeftInnerLabiNasi (-1.0020 0.2170 8.4620) (-0.6380 2.0840 7.6610) 0.1 4.5 35.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftLabiNasi ^ self fromArray: #(LeftLabiNasi (-1.7760 -0.8340 8.2390) (-1.5600 1.8870 7.3320) 0.1 5.2 35.0 3.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftLateralCorigator ^ self fromArray: #(LeftLateralCorigator (-1.1700 4.6580 7.3560) (0.0000 3.2620 8.2080) 0.5 3.0 45.0 3.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftSecondaryFrontalis ^ self fromArray: #(LeftSecondaryFrontalis (-0.5840 3.0520 8.0550) (-0.9910 4.8620 8.0930) 0.1 4.8 45.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! leftZygomaticMajor ^ self fromArray: #(LeftZygomaticMajor (-1.5700 -2.2210 7.8200) (-3.8050 0.8680 6.6000) 0.1 4.8 45.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:05'! rightAngularDepressor ^ self fromArray: #(RightAngularDepressor (1.5700 -2.2210 8.0250) (2.5590 -4.2770 5.3510) 0.3 4.5 65.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightFrontalisInner ^ self fromArray: #(RightFrontalisInner (0.4870 3.6390 8.1010) (0.3540 6.2470 7.2290) 0.1 3.6 35.0 4.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightFrontalisMajor ^ self fromArray: #(RightFrontalisMajor (2.3810 3.8300 8.0000) (2.2440 6.3630 6.9690) 0.1 3.7 65.0 0.5)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightFrontalisOuter ^ self fromArray: #(RightFrontalisOuter (3.0950 3.9700 7.8950) (3.6390 5.6480 5.9450) 0.1 3.5 45.0 2.5)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightInnerLabiNasi ^ self fromArray: #(RightInnerLabiNasi (1.0020 0.2170 8.4620) (0.6380 2.0840 7.6610) 0.1 4.5 35.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightLabiNasi ^ self fromArray: #(RightLabiNasi (1.7760 -0.8340 8.2390) (1.5600 1.8870 7.3320) 0.1 5.2 35.0 3.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightLateralCorigator ^ self fromArray: #(RightLateralCorigator (1.1700 4.6580 7.3560) (0.0000 3.2620 8.2080) 0.5 3.0 45.0 3.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:06'! rightSecondaryFrontalis ^ self fromArray: #(RightSecondaryFrontalis (0.5840 3.0520 8.0550) (0.9910 4.8620 8.0930) 0.1 4.8 45.0 1.0)! ! !Muscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:07'! rightZygomaticMajor ^ self fromArray: #(RightZygomaticMajor (1.5700 -2.2210 7.8200) (3.8050 0.8680 6.6000) 0.1 4.8 45.0 1.0)! ! !SphincterMuscle class methodsFor: 'examples' stamp: 'len 1/13/2001 02:20'! obicularisOris ^ self new! ! !UpdatingSimpleSliderMorph methodsFor: 'accessing' stamp: 'len 9/28/1999 01:28'! getValueSelector: aSymbol getValueSelector _ aSymbol asSymbol! ! !UpdatingSimpleSliderMorph methodsFor: 'stepping and presenter' stamp: 'len 9/28/1999 01:27'! step super step. (target notNil and: [getValueSelector notNil]) ifTrue: [self adjustToValue: (target perform: getValueSelector)]! ! !UpdatingSimpleSliderMorph methodsFor: 'stepping and presenter' stamp: 'len 9/29/1999 03:52'! stepTime ^ 750! ! !Viseme methodsFor: 'initialization' stamp: 'len 1/29/2001 11:45'! initialize contractions _ Dictionary new! ! !Viseme methodsFor: 'accessing' stamp: 'len 1/29/2001 11:45'! at: muscleName ^ contractions at: muscleName! ! !Viseme methodsFor: 'accessing' stamp: 'len 1/29/2001 11:45'! at: muscleName put: aNumber ^ contractions at: muscleName put: aNumber! ! !Viseme methodsFor: 'playing' stamp: 'len 1/29/2001 11:45'! playOn: anAvatar contractions associationsDo: [ :assoc | (anAvatar muscles at: assoc key) contraction: assoc value]! ! !Viseme class methodsFor: 'instance creation' stamp: 'len 9/10/1999 03:06'! new ^ super new initialize! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:00'! anger ^ self new at: #LeftZygomaticMajor put: 0.00; at: #RightZygomaticMajor put: 0.00; at: #LeftAngularDepressor put: 0.70; at: #RightAngularDepressor put: 0.60; at: #LeftFrontalisInner put: 0.20; at: #RightFrontalisInner put: 0.00; at: #LeftFrontalisMajor put: 0.10; at: #RightFrontalisMajor put: 0.00; at: #LeftFrontalisOuter put: 2.00; at: #RightFrontalisOuter put: 2.00; at: #LeftLabiNasi put: 1.80; at: #RightLabiNasi put: 1.90; at: #LeftInnerLabiNasi put: 1.20; at: #RightInnerLabiNasi put: 1.10; at: #LeftLateralCorigator put: 1.40; at: #RightLateralCorigator put: 1.30; at: #LeftSecondaryFrontalis put: 0.20; at: #RightSecondaryFrontalis put: 0.30; yourself! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:00'! disgust ^ self new at: #LeftZygomaticMajor put: 0.80; at: #RightZygomaticMajor put: 0.10; at: #LeftAngularDepressor put: 0.00; at: #RightAngularDepressor put: 0.50; at: #LeftFrontalisInner put: 0.20; at: #RightFrontalisInner put: 0.00; at: #LeftFrontalisMajor put: 0.00; at: #RightFrontalisMajor put: 0.00; at: #LeftFrontalisOuter put: 0.40; at: #RightFrontalisOuter put: 1.70; at: #LeftLabiNasi put: 1.10; at: #RightLabiNasi put: 2.00; at: #LeftInnerLabiNasi put: 0.70; at: #RightInnerLabiNasi put: 0.20; at: #LeftLateralCorigator put: 2.30; at: #RightLateralCorigator put: 2.40; at: #LeftSecondaryFrontalis put: 0.00; at: #RightSecondaryFrontalis put: 0.00; yourself! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:01'! fear ^ self new at: #LeftZygomaticMajor put: 0.60; at: #RightZygomaticMajor put: 0.50; at: #LeftAngularDepressor put: 0.50; at: #RightAngularDepressor put: 0.50; at: #LeftFrontalisInner put: 0.20; at: #RightFrontalisInner put: 0.20; at: #LeftFrontalisMajor put: 0.60; at: #RightFrontalisMajor put: 0.50; at: #LeftFrontalisOuter put: 0.20; at: #RightFrontalisOuter put: 0.20; at: #LeftLabiNasi put: 0.20; at: #RightLabiNasi put: 0.20; at: #LeftInnerLabiNasi put: 0.10; at: #RightInnerLabiNasi put: 0.10; at: #LeftLateralCorigator put: 0.20; at: #RightLateralCorigator put: 0.20; at: #LeftSecondaryFrontalis put: 0.40; at: #RightSecondaryFrontalis put: 0.30; yourself! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:02'! happiness ^ self new at: #LeftZygomaticMajor put: 1.10; at: #RightZygomaticMajor put: 1.00; at: #LeftAngularDepressor put: 0.00; at: #RightAngularDepressor put: 0.00; at: #LeftFrontalisInner put: 0.80; at: #RightFrontalisInner put: 0.90; at: #LeftFrontalisMajor put: 0.20; at: #RightFrontalisMajor put: 0.20; at: #LeftFrontalisOuter put: 0.10; at: #RightFrontalisOuter put: 0.30; at: #LeftLabiNasi put: 0.00; at: #RightLabiNasi put: 0.00; at: #LeftInnerLabiNasi put: 0.00; at: #RightInnerLabiNasi put: 0.00; at: #LeftLateralCorigator put: 0.00; at: #RightLateralCorigator put: 0.00; at: #LeftSecondaryFrontalis put: 0.00; at: #RightSecondaryFrontalis put: 0.00; yourself! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:03'! sadness ^ self new at: #LeftZygomaticMajor put: 0.00; at: #RightZygomaticMajor put: 0.00; at: #LeftAngularDepressor put: 0.70; at: #RightAngularDepressor put: 0.70; at: #LeftFrontalisInner put: 3.10; at: #RightFrontalisInner put: 3.90; at: #LeftFrontalisMajor put: 0.00; at: #RightFrontalisMajor put: 0.00; at: #LeftFrontalisOuter put: 0.00; at: #RightFrontalisOuter put: 0.00; at: #LeftLabiNasi put: 0.20; at: #RightLabiNasi put: 0.70; at: #LeftInnerLabiNasi put: 0.20; at: #RightInnerLabiNasi put: 0.20; at: #LeftLateralCorigator put: 0.00; at: #RightLateralCorigator put: 0.00; at: #LeftSecondaryFrontalis put: 0.00; at: #RightSecondaryFrontalis put: 0.00; yourself! ! !Viseme class methodsFor: 'examples' stamp: 'len 1/13/2001 02:04'! surprise ^ self new at: #LeftZygomaticMajor put: 0.20; at: #RightZygomaticMajor put: 0.20; at: #LeftAngularDepressor put: 0.40; at: #RightAngularDepressor put: 0.40; at: #LeftFrontalisInner put: 1.40; at: #RightFrontalisInner put: 0.90; at: #LeftFrontalisMajor put: 0.50; at: #RightFrontalisMajor put: 0.40; at: #LeftFrontalisOuter put: 0.20; at: #RightFrontalisOuter put: 0.70; at: #LeftLabiNasi put: 0.00; at: #RightLabiNasi put: 0.00; at: #LeftInnerLabiNasi put: 0.00; at: #RightInnerLabiNasi put: 0.10; at: #LeftLateralCorigator put: 0.00; at: #RightLateralCorigator put: 0.00; at: #LeftSecondaryFrontalis put: 0.50; at: #RightSecondaryFrontalis put: 0.60; yourself! !