SoftwareRenderer.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author ryg / http://farbrausch.de/~fg
  4. * @author mraleph / http://mrale.ph/
  5. * @author daoshengmu / http://dsmu.me/
  6. */
  7. THREE.SoftwareRenderer = function ( parameters ) {
  8. console.log( 'THREE.SoftwareRenderer', THREE.REVISION );
  9. parameters = parameters || {};
  10. var canvas = parameters.canvas !== undefined
  11. ? parameters.canvas
  12. : document.createElement( 'canvas' );
  13. var context = canvas.getContext( '2d', {
  14. alpha: parameters.alpha === true
  15. } );
  16. var alpha = parameters.alpha;
  17. var shaders = {};
  18. var textures = {};
  19. var canvasWidth, canvasHeight;
  20. var canvasWBlocks, canvasHBlocks;
  21. var viewportXScale, viewportYScale, viewportZScale;
  22. var viewportXOffs, viewportYOffs, viewportZOffs;
  23. var clearColor = new THREE.Color( 0x000000 );
  24. var imagedata, data, zbuffer;
  25. var numBlocks, blockMaxZ, blockFlags;
  26. var BLOCK_ISCLEAR = ( 1 << 0 );
  27. var BLOCK_NEEDCLEAR = ( 1 << 1 );
  28. var subpixelBits = 4;
  29. var subpixelBias = ( 1 << subpixelBits ) - 1;
  30. var blockShift = 3;
  31. var blockSize = 1 << blockShift;
  32. var maxZVal = ( 1 << 24 ); // Note: You want to size this so you don't get overflows.
  33. var lineMode = false;
  34. var lookVector = new THREE.Vector3( 0, 0, 1 );
  35. var crossVector = new THREE.Vector3();
  36. var rectx1 = Infinity, recty1 = Infinity;
  37. var rectx2 = 0, recty2 = 0;
  38. var prevrectx1 = Infinity, prevrecty1 = Infinity;
  39. var prevrectx2 = 0, prevrecty2 = 0;
  40. var projector = new THREE.Projector();
  41. var spriteV1 = new THREE.Vector4();
  42. var spriteV2 = new THREE.Vector4();
  43. var spriteV3 = new THREE.Vector4();
  44. var spriteUV1 = new THREE.Vector2();
  45. var spriteUV2 = new THREE.Vector2();
  46. var spriteUV3 = new THREE.Vector2();
  47. var mpVPool = [];
  48. var mpVPoolCount = 0;
  49. var mpNPool = [];
  50. var mpNPoolCount = 0;
  51. var mpUVPool = [];
  52. var mpUVPoolCount = 0;
  53. this.domElement = canvas;
  54. this.autoClear = true;
  55. // WebGLRenderer compatibility
  56. this.supportsVertexTextures = function () {};
  57. this.setFaceCulling = function () {};
  58. this.setClearColor = function ( color, alpha ) {
  59. clearColor.set( color );
  60. clearColorBuffer( clearColor );
  61. };
  62. this.setPixelRatio = function () {};
  63. this.setSize = function ( width, height ) {
  64. canvasWBlocks = Math.floor( width / blockSize );
  65. canvasHBlocks = Math.floor( height / blockSize );
  66. canvasWidth = canvasWBlocks * blockSize;
  67. canvasHeight = canvasHBlocks * blockSize;
  68. var fixScale = 1 << subpixelBits;
  69. viewportXScale = fixScale * canvasWidth / 2;
  70. viewportYScale = - fixScale * canvasHeight / 2;
  71. viewportZScale = maxZVal / 2;
  72. viewportXOffs = fixScale * canvasWidth / 2 + 0.5;
  73. viewportYOffs = fixScale * canvasHeight / 2 + 0.5;
  74. viewportZOffs = maxZVal / 2 + 0.5;
  75. canvas.width = canvasWidth;
  76. canvas.height = canvasHeight;
  77. context.fillStyle = alpha ? "rgba(0, 0, 0, 0)" : clearColor.getStyle();
  78. context.fillRect( 0, 0, canvasWidth, canvasHeight );
  79. imagedata = context.getImageData( 0, 0, canvasWidth, canvasHeight );
  80. data = imagedata.data;
  81. zbuffer = new Int32Array( data.length / 4 );
  82. numBlocks = canvasWBlocks * canvasHBlocks;
  83. blockMaxZ = new Int32Array( numBlocks );
  84. blockFlags = new Uint8Array( numBlocks );
  85. for ( var i = 0, l = zbuffer.length; i < l; i ++ ) {
  86. zbuffer[ i ] = maxZVal;
  87. }
  88. for ( var i = 0; i < numBlocks; i ++ ) {
  89. blockFlags[ i ] = BLOCK_ISCLEAR;
  90. }
  91. clearColorBuffer( clearColor );
  92. };
  93. this.setSize( canvas.width, canvas.height );
  94. this.clear = function () {
  95. rectx1 = Infinity;
  96. recty1 = Infinity;
  97. rectx2 = 0;
  98. recty2 = 0;
  99. mpVPoolCount = 0;
  100. mpNPoolCount = 0;
  101. mpUVPoolCount = 0;
  102. for ( var i = 0; i < numBlocks; i ++ ) {
  103. blockMaxZ[ i ] = maxZVal;
  104. blockFlags[ i ] = ( blockFlags[ i ] & BLOCK_ISCLEAR ) ? BLOCK_ISCLEAR : BLOCK_NEEDCLEAR;
  105. }
  106. };
  107. this.render = function ( scene, camera ) {
  108. // TODO: Check why autoClear can't be false.
  109. this.clear();
  110. var background = scene.background;
  111. if ( background && background.isColor ) {
  112. clearColorBuffer( background );
  113. }
  114. var renderData = projector.projectScene( scene, camera, false, false );
  115. var elements = renderData.elements;
  116. for ( var e = 0, el = elements.length; e < el; e ++ ) {
  117. var element = elements[ e ];
  118. var material = element.material;
  119. var shader = getMaterialShader( material );
  120. if ( !shader ) continue;
  121. if ( element instanceof THREE.RenderableFace ) {
  122. if ( ! element.uvs ) {
  123. drawTriangle(
  124. element.v1.positionScreen,
  125. element.v2.positionScreen,
  126. element.v3.positionScreen,
  127. null, null, null,
  128. shader, element, material
  129. );
  130. } else {
  131. drawTriangle(
  132. element.v1.positionScreen,
  133. element.v2.positionScreen,
  134. element.v3.positionScreen,
  135. element.uvs[ 0 ], element.uvs[ 1 ], element.uvs[ 2 ],
  136. shader, element, material
  137. );
  138. }
  139. } else if ( element instanceof THREE.RenderableSprite ) {
  140. var scaleX = element.scale.x * 0.5;
  141. var scaleY = element.scale.y * 0.5;
  142. spriteV1.copy( element );
  143. spriteV1.x -= scaleX;
  144. spriteV1.y += scaleY;
  145. spriteV2.copy( element );
  146. spriteV2.x -= scaleX;
  147. spriteV2.y -= scaleY;
  148. spriteV3.copy( element );
  149. spriteV3.x += scaleX;
  150. spriteV3.y += scaleY;
  151. if ( material.map ) {
  152. spriteUV1.set( 0, 1 );
  153. spriteUV2.set( 0, 0 );
  154. spriteUV3.set( 1, 1 );
  155. drawTriangle(
  156. spriteV1, spriteV2, spriteV3,
  157. spriteUV1, spriteUV2, spriteUV3,
  158. shader, element, material
  159. );
  160. } else {
  161. drawTriangle(
  162. spriteV1, spriteV2, spriteV3,
  163. null, null, null,
  164. shader, element, material
  165. );
  166. }
  167. spriteV1.copy( element );
  168. spriteV1.x += scaleX;
  169. spriteV1.y += scaleY;
  170. spriteV2.copy( element );
  171. spriteV2.x -= scaleX;
  172. spriteV2.y -= scaleY;
  173. spriteV3.copy( element );
  174. spriteV3.x += scaleX;
  175. spriteV3.y -= scaleY;
  176. if ( material.map ) {
  177. spriteUV1.set( 1, 1 );
  178. spriteUV2.set( 0, 0 );
  179. spriteUV3.set( 1, 0 );
  180. drawTriangle(
  181. spriteV1, spriteV2, spriteV3,
  182. spriteUV1, spriteUV2, spriteUV3,
  183. shader, element, material
  184. );
  185. } else {
  186. drawTriangle(
  187. spriteV1, spriteV2, spriteV3,
  188. null, null, null,
  189. shader, element, material
  190. );
  191. }
  192. } else if ( element instanceof THREE.RenderableLine ) {
  193. var shader = getMaterialShader( material );
  194. drawLine(
  195. element.v1.positionScreen,
  196. element.v2.positionScreen,
  197. element.vertexColors[0],
  198. element.vertexColors[1],
  199. shader,
  200. material
  201. );
  202. }
  203. }
  204. finishClear();
  205. var x = Math.min( rectx1, prevrectx1 );
  206. var y = Math.min( recty1, prevrecty1 );
  207. var width = Math.max( rectx2, prevrectx2 ) - x;
  208. var height = Math.max( recty2, prevrecty2 ) - y;
  209. /*
  210. // debug; draw zbuffer
  211. for ( var i = 0, l = zbuffer.length; i < l; i++ ) {
  212. var o = i * 4;
  213. var v = (65535 - zbuffer[ i ]) >> 3;
  214. data[ o + 0 ] = v;
  215. data[ o + 1 ] = v;
  216. data[ o + 2 ] = v;
  217. data[ o + 3 ] = 255;
  218. }
  219. */
  220. if ( x !== Infinity ) {
  221. context.putImageData( imagedata, 0, 0, x, y, width, height );
  222. }
  223. prevrectx1 = rectx1; prevrecty1 = recty1;
  224. prevrectx2 = rectx2; prevrecty2 = recty2;
  225. };
  226. function setSize( width, height ) {
  227. canvasWBlocks = Math.floor( width / blockSize );
  228. canvasHBlocks = Math.floor( height / blockSize );
  229. canvasWidth = canvasWBlocks * blockSize;
  230. canvasHeight = canvasHBlocks * blockSize;
  231. var fixScale = 1 << subpixelBits;
  232. viewportXScale = fixScale * canvasWidth / 2;
  233. viewportYScale = -fixScale * canvasHeight / 2;
  234. viewportZScale = maxZVal / 2;
  235. viewportXOffs = fixScale * canvasWidth / 2 + 0.5;
  236. viewportYOffs = fixScale * canvasHeight / 2 + 0.5;
  237. viewportZOffs = maxZVal / 2 + 0.5;
  238. canvas.width = canvasWidth;
  239. canvas.height = canvasHeight;
  240. context.fillStyle = alpha ? "rgba(0, 0, 0, 0)" : clearColor.getStyle();
  241. context.fillRect( 0, 0, canvasWidth, canvasHeight );
  242. imagedata = context.getImageData( 0, 0, canvasWidth, canvasHeight );
  243. data = imagedata.data;
  244. zbuffer = new Int32Array( data.length / 4 );
  245. numBlocks = canvasWBlocks * canvasHBlocks;
  246. blockMaxZ = new Int32Array( numBlocks );
  247. blockFlags = new Uint8Array( numBlocks );
  248. for ( var i = 0, l = zbuffer.length; i < l; i ++ ) {
  249. zbuffer[ i ] = maxZVal;
  250. }
  251. for ( var i = 0; i < numBlocks; i ++ ) {
  252. blockFlags[ i ] = BLOCK_ISCLEAR;
  253. }
  254. clearColorBuffer( clearColor );
  255. }
  256. function clearColorBuffer( color ) {
  257. var size = canvasWidth * canvasHeight * 4;
  258. for ( var i = 0; i < size; i += 4 ) {
  259. data[ i ] = color.r * 255 | 0;
  260. data[ i + 1 ] = color.g * 255 | 0;
  261. data[ i + 2 ] = color.b * 255 | 0;
  262. data[ i + 3 ] = alpha ? 0 : 255;
  263. }
  264. context.fillStyle = alpha ? "rgba(0, 0, 0, 0)" : color.getStyle();
  265. context.fillRect( 0, 0, canvasWidth, canvasHeight );
  266. }
  267. function getPalette( material, bSimulateSpecular ) {
  268. var i = 0, j = 0;
  269. var diffuseR = material.color.r * 255;
  270. var diffuseG = material.color.g * 255;
  271. var diffuseB = material.color.b * 255;
  272. var palette = new Uint8Array( 256 * 3 );
  273. if ( bSimulateSpecular ) {
  274. while ( i < 204 ) {
  275. palette[ j ++ ] = Math.min( i * diffuseR / 204, 255 );
  276. palette[ j ++ ] = Math.min( i * diffuseG / 204, 255 );
  277. palette[ j ++ ] = Math.min( i * diffuseB / 204, 255 );
  278. ++ i;
  279. }
  280. while ( i < 256 ) {
  281. // plus specular highlight
  282. palette[ j ++ ] = Math.min( diffuseR + ( i - 204 ) * ( 255 - diffuseR ) / 82, 255 );
  283. palette[ j ++ ] = Math.min( diffuseG + ( i - 204 ) * ( 255 - diffuseG ) / 82, 255 );
  284. palette[ j ++ ] = Math.min( diffuseB + ( i - 204 ) * ( 255 - diffuseB ) / 82, 255 );
  285. ++ i;
  286. }
  287. } else {
  288. while ( i < 256 ) {
  289. palette[ j ++ ] = Math.min( i * diffuseR / 255, 255 );
  290. palette[ j ++ ] = Math.min( i * diffuseG / 255, 255 );
  291. palette[ j ++ ] = Math.min( i * diffuseB / 255, 255 );
  292. ++ i;
  293. }
  294. }
  295. return palette;
  296. }
  297. function basicMaterialShader( buffer, depthBuf, offset, depth, u, v, n, face, material ) {
  298. var colorOffset = offset * 4;
  299. var texture = textures[ material.map.id ];
  300. if ( ! texture.data )
  301. return;
  302. var tdim = texture.width;
  303. var isTransparent = material.transparent;
  304. var tbound = tdim - 1;
  305. var tdata = texture.data;
  306. var tIndex = ( ( ( v * tdim ) & tbound ) * tdim + ( ( u * tdim ) & tbound ) ) * 4;
  307. if ( ! isTransparent ) {
  308. buffer[ colorOffset ] = tdata[ tIndex ];
  309. buffer[ colorOffset + 1 ] = tdata[ tIndex + 1 ];
  310. buffer[ colorOffset + 2 ] = tdata[ tIndex + 2 ];
  311. buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
  312. depthBuf[ offset ] = depth;
  313. } else {
  314. var srcR = tdata[ tIndex ];
  315. var srcG = tdata[ tIndex + 1 ];
  316. var srcB = tdata[ tIndex + 2 ];
  317. var opaci = tdata[ tIndex + 3 ] * material.opacity / 255;
  318. var destR = buffer[ colorOffset ];
  319. var destG = buffer[ colorOffset + 1 ];
  320. var destB = buffer[ colorOffset + 2 ];
  321. buffer[ colorOffset ] = ( srcR * opaci + destR * ( 1 - opaci ) );
  322. buffer[ colorOffset + 1 ] = ( srcG * opaci + destG * ( 1 - opaci ) );
  323. buffer[ colorOffset + 2 ] = ( srcB * opaci + destB * ( 1 - opaci ) );
  324. buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
  325. if ( buffer[ colorOffset + 3 ] == 255 ) // Only opaue pixls write to the depth buffer
  326. depthBuf[ offset ] = depth;
  327. }
  328. }
  329. function lightingMaterialShader( buffer, depthBuf, offset, depth, u, v, n, face, material ) {
  330. var colorOffset = offset * 4;
  331. var texture = textures[ material.map.id ];
  332. if ( ! texture.data )
  333. return;
  334. var tdim = texture.width;
  335. var isTransparent = material.transparent;
  336. var cIndex = ( n > 0 ? ( ~~ n ) : 0 ) * 3;
  337. var tbound = tdim - 1;
  338. var tdata = texture.data;
  339. var tIndex = ( ( ( v * tdim ) & tbound ) * tdim + ( ( u * tdim ) & tbound ) ) * 4;
  340. if ( ! isTransparent ) {
  341. buffer[ colorOffset ] = ( material.palette[ cIndex ] * tdata[ tIndex ] ) >> 8;
  342. buffer[ colorOffset + 1 ] = ( material.palette[ cIndex + 1 ] * tdata[ tIndex + 1 ] ) >> 8;
  343. buffer[ colorOffset + 2 ] = ( material.palette[ cIndex + 2 ] * tdata[ tIndex + 2 ] ) >> 8;
  344. buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
  345. depthBuf[ offset ] = depth;
  346. } else {
  347. var foreColorR = material.palette[ cIndex ] * tdata[ tIndex ];
  348. var foreColorG = material.palette[ cIndex + 1 ] * tdata[ tIndex + 1 ];
  349. var foreColorB = material.palette[ cIndex + 2 ] * tdata[ tIndex + 2 ];
  350. var opaci = tdata[ tIndex + 3 ] * material.opacity / 256;
  351. var destR = buffer[ colorOffset ];
  352. var destG = buffer[ colorOffset + 1 ];
  353. var destB = buffer[ colorOffset + 2 ];
  354. buffer[ colorOffset ] = foreColorR * opaci + destR * ( 1 - opaci );
  355. buffer[ colorOffset + 1 ] = foreColorG * opaci + destG * ( 1 - opaci );
  356. buffer[ colorOffset + 2 ] = foreColorB * opaci + destB * ( 1 - opaci );
  357. buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
  358. if ( buffer[ colorOffset + 3 ] == 255 ) // Only opaue pixls write to the depth buffer
  359. depthBuf[ offset ] = depth;
  360. }
  361. }
  362. function onMaterialUpdate ( event ) {
  363. var material = event.target;
  364. material.removeEventListener( 'update', onMaterialUpdate );
  365. delete shaders[ material.id ];
  366. }
  367. function getMaterialShader( material ) {
  368. var id = material.id;
  369. var shader = shaders[ id ];
  370. if ( shader && material.map && !textures[ material.map.id ] ) delete shaders[ id ];
  371. if ( shaders[ id ] === undefined ) {
  372. material.addEventListener( 'update', onMaterialUpdate );
  373. if ( material instanceof THREE.MeshBasicMaterial ||
  374. material instanceof THREE.MeshLambertMaterial ||
  375. material instanceof THREE.MeshPhongMaterial ||
  376. material instanceof THREE.SpriteMaterial ) {
  377. if ( material instanceof THREE.MeshLambertMaterial ) {
  378. // Generate color palette
  379. if ( ! material.palette ) {
  380. material.palette = getPalette( material, false );
  381. }
  382. } else if ( material instanceof THREE.MeshPhongMaterial ) {
  383. // Generate color palette
  384. if ( ! material.palette ) {
  385. material.palette = getPalette( material, true );
  386. }
  387. }
  388. var string;
  389. if ( material.map ) {
  390. var texture = new THREE.SoftwareRenderer.Texture();
  391. texture.fromImage( material.map.image );
  392. if ( !texture.data ) return;
  393. textures[ material.map.id ] = texture;
  394. if ( material instanceof THREE.MeshBasicMaterial
  395. || material instanceof THREE.SpriteMaterial ) {
  396. shader = basicMaterialShader;
  397. } else {
  398. shader = lightingMaterialShader;
  399. }
  400. } else {
  401. if ( material.vertexColors === THREE.FaceColors ) {
  402. string = [
  403. 'var colorOffset = offset * 4;',
  404. 'buffer[ colorOffset ] = face.color.r * 255;',
  405. 'buffer[ colorOffset + 1 ] = face.color.g * 255;',
  406. 'buffer[ colorOffset + 2 ] = face.color.b * 255;',
  407. 'buffer[ colorOffset + 3 ] = material.opacity * 255;',
  408. 'depthBuf[ offset ] = depth;'
  409. ].join( '\n' );
  410. } else {
  411. string = [
  412. 'var colorOffset = offset * 4;',
  413. 'buffer[ colorOffset ] = material.color.r * 255;',
  414. 'buffer[ colorOffset + 1 ] = material.color.g * 255;',
  415. 'buffer[ colorOffset + 2 ] = material.color.b * 255;',
  416. 'buffer[ colorOffset + 3 ] = material.opacity * 255;',
  417. 'depthBuf[ offset ] = depth;'
  418. ].join( '\n' );
  419. }
  420. shader = new Function( 'buffer, depthBuf, offset, depth, u, v, n, face, material', string );
  421. }
  422. } else if ( material instanceof THREE.LineBasicMaterial ) {
  423. var string = [
  424. 'var colorOffset = offset * 4;',
  425. 'buffer[ colorOffset ] = material.color.r * (color1.r+color2.r) * 0.5 * 255;',
  426. 'buffer[ colorOffset + 1 ] = material.color.g * (color1.g+color2.g) * 0.5 * 255;',
  427. 'buffer[ colorOffset + 2 ] = material.color.b * (color1.b+color2.b) * 0.5 * 255;',
  428. 'buffer[ colorOffset + 3 ] = 255;',
  429. 'depthBuf[ offset ] = depth;'
  430. ].join('\n');
  431. shader = new Function( 'buffer, depthBuf, offset, depth, color1, color2, material', string );
  432. } else {
  433. var string = [
  434. 'var colorOffset = offset * 4;',
  435. 'buffer[ colorOffset ] = u * 255;',
  436. 'buffer[ colorOffset + 1 ] = v * 255;',
  437. 'buffer[ colorOffset + 2 ] = 0;',
  438. 'buffer[ colorOffset + 3 ] = 255;',
  439. 'depthBuf[ offset ] = depth;'
  440. ].join( '\n' );
  441. shader = new Function( 'buffer, depthBuf, offset, depth, u, v, n, face, material', string );
  442. }
  443. shaders[ id ] = shader;
  444. }
  445. return shader;
  446. }
  447. function clearRectangle( x1, y1, x2, y2 ) {
  448. var xmin = Math.max( Math.min( x1, x2 ), 0 );
  449. var xmax = Math.min( Math.max( x1, x2 ), canvasWidth );
  450. var ymin = Math.max( Math.min( y1, y2 ), 0 );
  451. var ymax = Math.min( Math.max( y1, y2 ), canvasHeight );
  452. var offset = ( xmin + ymin * canvasWidth ) * 4 + 3;
  453. var linestep = ( canvasWidth - ( xmax - xmin ) ) * 4;
  454. for ( var y = ymin; y < ymax; y ++ ) {
  455. for ( var x = xmin; x < xmax; x ++ ) {
  456. data[ offset += 4 ] = 0;
  457. }
  458. offset += linestep;
  459. }
  460. }
  461. function drawTriangle( v1, v2, v3, uv1, uv2, uv3, shader, face, material ) {
  462. // TODO: Implement per-pixel z-clipping
  463. if ( v1.z < - 1 || v1.z > 1 || v2.z < - 1 || v2.z > 1 || v3.z < - 1 || v3.z > 1 ) return;
  464. // https://gist.github.com/2486101
  465. // explanation: http://pouet.net/topic.php?which=8760&page=1
  466. var fixscale = ( 1 << subpixelBits );
  467. // 28.4 fixed-point coordinates
  468. var x1 = ( v1.x * viewportXScale + viewportXOffs ) | 0;
  469. var x2 = ( v2.x * viewportXScale + viewportXOffs ) | 0;
  470. var x3 = ( v3.x * viewportXScale + viewportXOffs ) | 0;
  471. var y1 = ( v1.y * viewportYScale + viewportYOffs ) | 0;
  472. var y2 = ( v2.y * viewportYScale + viewportYOffs ) | 0;
  473. var y3 = ( v3.y * viewportYScale + viewportYOffs ) | 0;
  474. var bHasNormal = face.vertexNormalsModel && face.vertexNormalsModel.length;
  475. var bHasUV = uv1 && uv2 && uv3;
  476. var longestSide = Math.max(
  477. Math.sqrt( (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) ),
  478. Math.sqrt( (x2 - x3)*(x2 - x3) + (y2 - y3)*(y2 - y3) ),
  479. Math.sqrt( (x3 - x1)*(x3 - x1) + (y3 - y1)*(y3 - y1) )
  480. );
  481. if( !(face instanceof THREE.RenderableSprite)
  482. && (longestSide > 100 * fixscale) ) {
  483. // 1
  484. // |\
  485. // |a\
  486. // |__\
  487. // |\c|\
  488. // |b\|d\
  489. // |__\__\
  490. // 2 3
  491. var tempFace = { vertexNormalsModel : [],
  492. color : face.color };
  493. var mpUV12, mpUV23, mpUV31;
  494. if ( bHasUV ) {
  495. if ( mpUVPoolCount === mpUVPool.length ) {
  496. mpUV12 = new THREE.Vector2();
  497. mpUVPool.push( mpUV12 );
  498. ++mpUVPoolCount;
  499. mpUV23 = new THREE.Vector2();
  500. mpUVPool.push( mpUV23 );
  501. ++mpUVPoolCount;
  502. mpUV31 = new THREE.Vector2();
  503. mpUVPool.push( mpUV31 );
  504. ++mpUVPoolCount;
  505. } else {
  506. mpUV12 = mpUVPool[ mpUVPoolCount ];
  507. ++mpUVPoolCount;
  508. mpUV23 = mpUVPool[ mpUVPoolCount ];
  509. ++mpUVPoolCount;
  510. mpUV31 = mpUVPool[ mpUVPoolCount ];
  511. ++mpUVPoolCount;
  512. }
  513. var weight;
  514. weight = (1 + v2.z) * (v2.w / v1.w) / (1 + v1.z);
  515. mpUV12.copy( uv1 ).multiplyScalar( weight ).add( uv2 ).multiplyScalar( 1 / (weight + 1) );
  516. weight = (1 + v3.z) * (v3.w / v2.w) / (1 + v2.z);
  517. mpUV23.copy( uv2 ).multiplyScalar( weight ).add( uv3 ).multiplyScalar( 1 / (weight + 1) );
  518. weight = (1 + v1.z) * (v1.w / v3.w) / (1 + v3.z);
  519. mpUV31.copy( uv3 ).multiplyScalar( weight ).add( uv1 ).multiplyScalar( 1 / (weight + 1) );
  520. }
  521. var mpV12, mpV23, mpV31;
  522. if ( mpVPoolCount === mpVPool.length ) {
  523. mpV12 = new THREE.Vector4();
  524. mpVPool.push( mpV12 );
  525. ++mpVPoolCount;
  526. mpV23 = new THREE.Vector4();
  527. mpVPool.push( mpV23 );
  528. ++mpVPoolCount;
  529. mpV31 = new THREE.Vector4();
  530. mpVPool.push( mpV31 );
  531. ++mpVPoolCount;
  532. } else {
  533. mpV12 = mpVPool[ mpVPoolCount ];
  534. ++mpVPoolCount;
  535. mpV23 = mpVPool[ mpVPoolCount ];
  536. ++mpVPoolCount;
  537. mpV31 = mpVPool[ mpVPoolCount ];
  538. ++mpVPoolCount;
  539. }
  540. mpV12.copy( v1 ).add( v2 ).multiplyScalar( 0.5 );
  541. mpV23.copy( v2 ).add( v3 ).multiplyScalar( 0.5 );
  542. mpV31.copy( v3 ).add( v1 ).multiplyScalar( 0.5 );
  543. var mpN12, mpN23, mpN31;
  544. if( bHasNormal ) {
  545. if ( mpNPoolCount === mpNPool.length ) {
  546. mpN12 = new THREE.Vector3();
  547. mpNPool.push( mpN12 );
  548. ++mpNPoolCount;
  549. mpN23 = new THREE.Vector3();
  550. mpNPool.push( mpN23 );
  551. ++mpNPoolCount;
  552. mpN31 = new THREE.Vector3();
  553. mpNPool.push( mpN31 );
  554. ++mpNPoolCount;
  555. } else {
  556. mpN12 = mpNPool[ mpNPoolCount ];
  557. ++mpNPoolCount;
  558. mpN23 = mpNPool[ mpNPoolCount ];
  559. ++mpNPoolCount;
  560. mpN31 = mpNPool[ mpNPoolCount ];
  561. ++mpNPoolCount;
  562. }
  563. mpN12.copy( face.vertexNormalsModel[ 0 ] ).add( face.vertexNormalsModel[ 1 ] ).normalize();
  564. mpN23.copy( face.vertexNormalsModel[ 1 ] ).add( face.vertexNormalsModel[ 2 ] ).normalize();
  565. mpN31.copy( face.vertexNormalsModel[ 2 ] ).add( face.vertexNormalsModel[ 0 ] ).normalize();
  566. }
  567. // a
  568. if( bHasNormal ) {
  569. tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 0 ];
  570. tempFace.vertexNormalsModel[ 1 ] = mpN12;
  571. tempFace.vertexNormalsModel[ 2 ] = mpN31;
  572. }
  573. drawTriangle( v1, mpV12, mpV31, uv1, mpUV12, mpUV31, shader, tempFace, material );
  574. // b
  575. if( bHasNormal ) {
  576. tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 1 ];
  577. tempFace.vertexNormalsModel[ 1 ] = mpN23;
  578. tempFace.vertexNormalsModel[ 2 ] = mpN12;
  579. }
  580. drawTriangle( v2, mpV23, mpV12, uv2, mpUV23, mpUV12, shader, tempFace, material );
  581. // c
  582. if( bHasNormal ) {
  583. tempFace.vertexNormalsModel[ 0 ] = mpN12;
  584. tempFace.vertexNormalsModel[ 1 ] = mpN23;
  585. tempFace.vertexNormalsModel[ 2 ] = mpN31;
  586. }
  587. drawTriangle( mpV12, mpV23, mpV31, mpUV12, mpUV23, mpUV31, shader, tempFace, material );
  588. // d
  589. if( bHasNormal ) {
  590. tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 2 ];
  591. tempFace.vertexNormalsModel[ 1 ] = mpN31;
  592. tempFace.vertexNormalsModel[ 2 ] = mpN23;
  593. }
  594. drawTriangle( v3, mpV31, mpV23, uv3, mpUV31, mpUV23, shader, tempFace, material );
  595. return;
  596. }
  597. // Z values (.28 fixed-point)
  598. var z1 = ( v1.z * viewportZScale + viewportZOffs ) | 0;
  599. var z2 = ( v2.z * viewportZScale + viewportZOffs ) | 0;
  600. var z3 = ( v3.z * viewportZScale + viewportZOffs ) | 0;
  601. // UV values
  602. var bHasUV = false;
  603. var tu1, tv1, tu2, tv2, tu3, tv3;
  604. if ( uv1 && uv2 && uv3 ) {
  605. bHasUV = true;
  606. tu1 = uv1.x;
  607. tv1 = 1 - uv1.y;
  608. tu2 = uv2.x;
  609. tv2 = 1 - uv2.y;
  610. tu3 = uv3.x;
  611. tv3 = 1 - uv3.y;
  612. }
  613. // Normal values
  614. var n1, n2, n3, nz1, nz2, nz3;
  615. if ( bHasNormal ) {
  616. n1 = face.vertexNormalsModel[ 0 ];
  617. n2 = face.vertexNormalsModel[ 1 ];
  618. n3 = face.vertexNormalsModel[ 2 ];
  619. nz1 = n1.z * 255;
  620. nz2 = n2.z * 255;
  621. nz3 = n3.z * 255;
  622. }
  623. // Deltas
  624. var dx12 = x1 - x2, dy12 = y2 - y1;
  625. var dx23 = x2 - x3, dy23 = y3 - y2;
  626. var dx31 = x3 - x1, dy31 = y1 - y3;
  627. // Bounding rectangle
  628. var minx = Math.max( ( Math.min( x1, x2, x3 ) + subpixelBias ) >> subpixelBits, 0 );
  629. var maxx = Math.min( ( Math.max( x1, x2, x3 ) + subpixelBias ) >> subpixelBits, canvasWidth );
  630. var miny = Math.max( ( Math.min( y1, y2, y3 ) + subpixelBias ) >> subpixelBits, 0 );
  631. var maxy = Math.min( ( Math.max( y1, y2, y3 ) + subpixelBias ) >> subpixelBits, canvasHeight );
  632. rectx1 = Math.min( minx, rectx1 );
  633. rectx2 = Math.max( maxx, rectx2 );
  634. recty1 = Math.min( miny, recty1 );
  635. recty2 = Math.max( maxy, recty2 );
  636. // Block size, standard 8x8 (must be power of two)
  637. var q = blockSize;
  638. // Start in corner of 8x8 block
  639. minx &= ~ ( q - 1 );
  640. miny &= ~ ( q - 1 );
  641. // Constant part of half-edge functions
  642. var minXfixscale = ( minx << subpixelBits );
  643. var minYfixscale = ( miny << subpixelBits );
  644. var c1 = dy12 * ( ( minXfixscale ) - x1 ) + dx12 * ( ( minYfixscale ) - y1 );
  645. var c2 = dy23 * ( ( minXfixscale ) - x2 ) + dx23 * ( ( minYfixscale ) - y2 );
  646. var c3 = dy31 * ( ( minXfixscale ) - x3 ) + dx31 * ( ( minYfixscale ) - y3 );
  647. // Correct for fill convention
  648. if ( dy12 > 0 || ( dy12 == 0 && dx12 > 0 ) ) c1 ++;
  649. if ( dy23 > 0 || ( dy23 == 0 && dx23 > 0 ) ) c2 ++;
  650. if ( dy31 > 0 || ( dy31 == 0 && dx31 > 0 ) ) c3 ++;
  651. // Note this doesn't kill subpixel precision, but only because we test for >=0 (not >0).
  652. // It's a bit subtle. :)
  653. c1 = ( c1 - 1 ) >> subpixelBits;
  654. c2 = ( c2 - 1 ) >> subpixelBits;
  655. c3 = ( c3 - 1 ) >> subpixelBits;
  656. // Z interpolation setup
  657. var dz12 = z1 - z2, dz31 = z3 - z1;
  658. var invDet = 1.0 / ( dx12 * dy31 - dx31 * dy12 );
  659. var dzdx = ( invDet * ( dz12 * dy31 - dz31 * dy12 ) ); // dz per one subpixel step in x
  660. var dzdy = ( invDet * ( dz12 * dx31 - dx12 * dz31 ) ); // dz per one subpixel step in y
  661. // Z at top/left corner of rast area
  662. var cz = ( z1 + ( ( minXfixscale ) - x1 ) * dzdx + ( ( minYfixscale ) - y1 ) * dzdy ) | 0;
  663. // Z pixel steps
  664. dzdx = ( dzdx * fixscale ) | 0;
  665. dzdy = ( dzdy * fixscale ) | 0;
  666. var dtvdx, dtvdy, cbtu, cbtv;
  667. if ( bHasUV ) {
  668. // UV interpolation setup
  669. var dtu12 = tu1 - tu2, dtu31 = tu3 - tu1;
  670. var dtudx = ( invDet * ( dtu12 * dy31 - dtu31 * dy12 ) ); // dtu per one subpixel step in x
  671. var dtudy = ( invDet * ( dtu12 * dx31 - dx12 * dtu31 ) ); // dtu per one subpixel step in y
  672. var dtv12 = tv1 - tv2, dtv31 = tv3 - tv1;
  673. dtvdx = ( invDet * ( dtv12 * dy31 - dtv31 * dy12 ) ); // dtv per one subpixel step in x
  674. dtvdy = ( invDet * ( dtv12 * dx31 - dx12 * dtv31 ) ); // dtv per one subpixel step in y
  675. // UV at top/left corner of rast area
  676. cbtu = ( tu1 + ( minXfixscale - x1 ) * dtudx + ( minYfixscale - y1 ) * dtudy );
  677. cbtv = ( tv1 + ( minXfixscale - x1 ) * dtvdx + ( minYfixscale - y1 ) * dtvdy );
  678. // UV pixel steps
  679. dtudx = dtudx * fixscale;
  680. dtudy = dtudy * fixscale;
  681. dtvdx = dtvdx * fixscale;
  682. dtvdy = dtvdy * fixscale;
  683. }
  684. var dnxdx, dnzdy, cbnz;
  685. if ( bHasNormal ) {
  686. // Normal interpolation setup
  687. var dnz12 = nz1 - nz2, dnz31 = nz3 - nz1;
  688. var dnzdx = ( invDet * ( dnz12 * dy31 - dnz31 * dy12 ) ); // dnz per one subpixel step in x
  689. var dnzdy = ( invDet * ( dnz12 * dx31 - dx12 * dnz31 ) ); // dnz per one subpixel step in y
  690. // Normal at top/left corner of rast area
  691. cbnz = ( nz1 + ( minXfixscale - x1 ) * dnzdx + ( minYfixscale - y1 ) * dnzdy );
  692. // Normal pixel steps
  693. dnzdx = ( dnzdx * fixscale );
  694. dnzdy = ( dnzdy * fixscale );
  695. }
  696. // Set up min/max corners
  697. var qm1 = q - 1; // for convenience
  698. var nmin1 = 0, nmax1 = 0;
  699. var nmin2 = 0, nmax2 = 0;
  700. var nmin3 = 0, nmax3 = 0;
  701. var nminz = 0, nmaxz = 0;
  702. if ( dx12 >= 0 ) nmax1 -= qm1 * dx12; else nmin1 -= qm1 * dx12;
  703. if ( dy12 >= 0 ) nmax1 -= qm1 * dy12; else nmin1 -= qm1 * dy12;
  704. if ( dx23 >= 0 ) nmax2 -= qm1 * dx23; else nmin2 -= qm1 * dx23;
  705. if ( dy23 >= 0 ) nmax2 -= qm1 * dy23; else nmin2 -= qm1 * dy23;
  706. if ( dx31 >= 0 ) nmax3 -= qm1 * dx31; else nmin3 -= qm1 * dx31;
  707. if ( dy31 >= 0 ) nmax3 -= qm1 * dy31; else nmin3 -= qm1 * dy31;
  708. if ( dzdx >= 0 ) nmaxz += qm1 * dzdx; else nminz += qm1 * dzdx;
  709. if ( dzdy >= 0 ) nmaxz += qm1 * dzdy; else nminz += qm1 * dzdy;
  710. // Loop through blocks
  711. var linestep = canvasWidth - q;
  712. var cb1 = c1;
  713. var cb2 = c2;
  714. var cb3 = c3;
  715. var cbz = cz;
  716. var qstep = - q;
  717. var e1x = qstep * dy12;
  718. var e2x = qstep * dy23;
  719. var e3x = qstep * dy31;
  720. var ezx = qstep * dzdx;
  721. var etux, etvx;
  722. if ( bHasUV ) {
  723. etux = qstep * dtudx;
  724. etvx = qstep * dtvdx;
  725. }
  726. var enzx;
  727. if ( bHasNormal ) {
  728. enzx = qstep * dnzdx;
  729. }
  730. var x0 = minx;
  731. for ( var y0 = miny; y0 < maxy; y0 += q ) {
  732. // New block line - keep hunting for tri outer edge in old block line dir
  733. while ( x0 >= minx && x0 < maxx && cb1 >= nmax1 && cb2 >= nmax2 && cb3 >= nmax3 ) {
  734. x0 += qstep;
  735. cb1 += e1x;
  736. cb2 += e2x;
  737. cb3 += e3x;
  738. cbz += ezx;
  739. if ( bHasUV ) {
  740. cbtu += etux;
  741. cbtv += etvx;
  742. }
  743. if ( bHasNormal ) {
  744. cbnz += enzx;
  745. }
  746. }
  747. // Okay, we're now in a block we know is outside. Reverse direction and go into main loop.
  748. qstep = - qstep;
  749. e1x = - e1x;
  750. e2x = - e2x;
  751. e3x = - e3x;
  752. ezx = - ezx;
  753. if ( bHasUV ) {
  754. etux = - etux;
  755. etvx = - etvx;
  756. }
  757. if ( bHasNormal ) {
  758. enzx = - enzx;
  759. }
  760. while ( 1 ) {
  761. // Step everything
  762. x0 += qstep;
  763. cb1 += e1x;
  764. cb2 += e2x;
  765. cb3 += e3x;
  766. cbz += ezx;
  767. if ( bHasUV ) {
  768. cbtu += etux;
  769. cbtv += etvx;
  770. }
  771. if ( bHasNormal ) {
  772. cbnz += enzx;
  773. }
  774. // We're done with this block line when at least one edge completely out
  775. // If an edge function is too small and decreasing in the current traversal
  776. // dir, we're done with this line.
  777. if ( x0 < minx || x0 >= maxx ) break;
  778. if ( cb1 < nmax1 ) if ( e1x < 0 ) break; else continue;
  779. if ( cb2 < nmax2 ) if ( e2x < 0 ) break; else continue;
  780. if ( cb3 < nmax3 ) if ( e3x < 0 ) break; else continue;
  781. // We can skip this block if it's already fully covered
  782. var blockX = x0 >> blockShift;
  783. var blockY = y0 >> blockShift;
  784. var blockId = blockX + blockY * canvasWBlocks;
  785. var minz = cbz + nminz;
  786. // farthest point in block closer than closest point in our tri?
  787. if ( blockMaxZ[ blockId ] < minz ) continue;
  788. // Need to do a deferred clear?
  789. var bflags = blockFlags[ blockId ];
  790. if ( bflags & BLOCK_NEEDCLEAR ) clearBlock( blockX, blockY );
  791. blockFlags[ blockId ] = bflags & ~ ( BLOCK_ISCLEAR | BLOCK_NEEDCLEAR );
  792. // Offset at top-left corner
  793. var offset = x0 + y0 * canvasWidth;
  794. // Accept whole block when fully covered
  795. if ( cb1 >= nmin1 && cb2 >= nmin2 && cb3 >= nmin3 ) {
  796. var maxz = cbz + nmaxz;
  797. blockMaxZ[ blockId ] = Math.min( blockMaxZ[ blockId ], maxz );
  798. var cy1 = cb1;
  799. var cy2 = cb2;
  800. var cyz = cbz;
  801. var cytu, cytv;
  802. if ( bHasUV ) {
  803. cytu = cbtu;
  804. cytv = cbtv;
  805. }
  806. var cynz;
  807. if ( bHasNormal ) {
  808. cynz = cbnz;
  809. }
  810. for ( var iy = 0; iy < q; iy ++ ) {
  811. var cx1 = cy1;
  812. var cx2 = cy2;
  813. var cxz = cyz;
  814. var cxtu;
  815. var cxtv;
  816. if ( bHasUV ) {
  817. cxtu = cytu;
  818. cxtv = cytv;
  819. }
  820. var cxnz;
  821. if ( bHasNormal ) {
  822. cxnz = cynz;
  823. }
  824. for ( var ix = 0; ix < q; ix ++ ) {
  825. var z = cxz;
  826. if ( z < zbuffer[ offset ] ) {
  827. shader( data, zbuffer, offset, z, cxtu, cxtv, cxnz, face, material );
  828. }
  829. cx1 += dy12;
  830. cx2 += dy23;
  831. cxz += dzdx;
  832. if ( bHasUV ) {
  833. cxtu += dtudx;
  834. cxtv += dtvdx;
  835. }
  836. if ( bHasNormal ) {
  837. cxnz += dnzdx;
  838. }
  839. offset ++;
  840. }
  841. cy1 += dx12;
  842. cy2 += dx23;
  843. cyz += dzdy;
  844. if ( bHasUV ) {
  845. cytu += dtudy;
  846. cytv += dtvdy;
  847. }
  848. if ( bHasNormal ) {
  849. cynz += dnzdy;
  850. }
  851. offset += linestep;
  852. }
  853. } else {
  854. // Partially covered block
  855. var cy1 = cb1;
  856. var cy2 = cb2;
  857. var cy3 = cb3;
  858. var cyz = cbz;
  859. var cytu, cytv;
  860. if ( bHasUV ) {
  861. cytu = cbtu;
  862. cytv = cbtv;
  863. }
  864. var cynz;
  865. if ( bHasNormal ) {
  866. cynz = cbnz;
  867. }
  868. for ( var iy = 0; iy < q; iy ++ ) {
  869. var cx1 = cy1;
  870. var cx2 = cy2;
  871. var cx3 = cy3;
  872. var cxz = cyz;
  873. var cxtu;
  874. var cxtv;
  875. if ( bHasUV ) {
  876. cxtu = cytu;
  877. cxtv = cytv;
  878. }
  879. var cxnz;
  880. if ( bHasNormal ) {
  881. cxnz = cynz;
  882. }
  883. for ( var ix = 0; ix < q; ix ++ ) {
  884. if ( ( cx1 | cx2 | cx3 ) >= 0 ) {
  885. var z = cxz;
  886. if ( z < zbuffer[ offset ] ) {
  887. shader( data, zbuffer, offset, z, cxtu, cxtv, cxnz, face, material );
  888. }
  889. }
  890. cx1 += dy12;
  891. cx2 += dy23;
  892. cx3 += dy31;
  893. cxz += dzdx;
  894. if ( bHasUV ) {
  895. cxtu += dtudx;
  896. cxtv += dtvdx;
  897. }
  898. if ( bHasNormal ) {
  899. cxnz += dnzdx;
  900. }
  901. offset ++;
  902. }
  903. cy1 += dx12;
  904. cy2 += dx23;
  905. cy3 += dx31;
  906. cyz += dzdy;
  907. if ( bHasUV ) {
  908. cytu += dtudy;
  909. cytv += dtvdy;
  910. }
  911. if ( bHasNormal ) {
  912. cynz += dnzdy;
  913. }
  914. offset += linestep;
  915. }
  916. }
  917. }
  918. // Advance to next row of blocks
  919. cb1 += q * dx12;
  920. cb2 += q * dx23;
  921. cb3 += q * dx31;
  922. cbz += q * dzdy;
  923. if ( bHasUV ) {
  924. cbtu += q * dtudy;
  925. cbtv += q * dtvdy;
  926. }
  927. if ( bHasNormal ) {
  928. cbnz += q * dnzdy;
  929. }
  930. }
  931. }
  932. // When drawing line, the blockShiftShift has to be zero. In order to clean pixel
  933. // Using color1 and color2 to interpolation pixel color
  934. // LineWidth is according to material.linewidth
  935. function drawLine( v1, v2, color1, color2, shader, material ) {
  936. // While the line mode is enable, blockSize has to be changed to 0.
  937. if ( !lineMode ) {
  938. lineMode = true;
  939. blockShift = 0;
  940. blockSize = 1 << blockShift;
  941. setSize( canvas.width, canvas.height );
  942. }
  943. // TODO: Implement per-pixel z-clipping
  944. if ( v1.z < -1 || v1.z > 1 || v2.z < -1 || v2.z > 1 ) return;
  945. var halfLineWidth = Math.floor( ( material.linewidth - 1 ) * 0.5 );
  946. // https://gist.github.com/2486101
  947. // explanation: http://pouet.net/topic.php?which=8760&page=1
  948. // 28.4 fixed-point coordinates
  949. var x1 = ( v1.x * viewportXScale + viewportXOffs ) | 0;
  950. var x2 = ( v2.x * viewportXScale + viewportXOffs ) | 0;
  951. var y1 = ( v1.y * viewportYScale + viewportYOffs ) | 0;
  952. var y2 = ( v2.y * viewportYScale + viewportYOffs ) | 0;
  953. var z1 = ( v1.z * viewportZScale + viewportZOffs ) | 0;
  954. var z2 = ( v2.z * viewportZScale + viewportZOffs ) | 0;
  955. // Deltas
  956. var dx12 = x1 - x2, dy12 = y1 - y2, dz12 = z1 - z2;
  957. // Bounding rectangle
  958. var minx = Math.max( ( Math.min( x1, x2 ) + subpixelBias ) >> subpixelBits, 0 );
  959. var maxx = Math.min( ( Math.max( x1, x2 ) + subpixelBias ) >> subpixelBits, canvasWidth );
  960. var miny = Math.max( ( Math.min( y1, y2 ) + subpixelBias ) >> subpixelBits, 0 );
  961. var maxy = Math.min( ( Math.max( y1, y2 ) + subpixelBias ) >> subpixelBits, canvasHeight );
  962. var minz = Math.max( ( Math.min( z1, z2 ) + subpixelBias ) >> subpixelBits, 0 );
  963. var maxz = ( Math.max( z1, z2 ) + subpixelBias ) >> subpixelBits;
  964. rectx1 = Math.min( minx, rectx1 );
  965. rectx2 = Math.max( maxx, rectx2 );
  966. recty1 = Math.min( miny, recty1 );
  967. recty2 = Math.max( maxy, recty2 );
  968. // Get the line's unit vector and cross vector
  969. var length = Math.sqrt( ( dy12 * dy12 ) + ( dx12 * dx12 ) );
  970. var unitX = ( dx12 / length );
  971. var unitY = ( dy12 / length );
  972. var unitZ = ( dz12 / length );
  973. var pixelX, pixelY, pixelZ;
  974. var pX, pY, pZ;
  975. crossVector.set( unitX, unitY, unitZ );
  976. crossVector.cross( lookVector );
  977. crossVector.normalize();
  978. while (length > 0) {
  979. // Get this pixel.
  980. pixelX = x2 + length * unitX;
  981. pixelY = y2 + length * unitY;
  982. pixelZ = z2 + length * unitZ;
  983. pixelX = ( pixelX + subpixelBias ) >> subpixelBits;
  984. pixelY = ( pixelY + subpixelBias ) >> subpixelBits;
  985. pZ = ( pixelZ + subpixelBias ) >> subpixelBits;
  986. // Draw line with line width
  987. for ( var i = -halfLineWidth; i <= halfLineWidth; ++i ) {
  988. // Compute the line pixels.
  989. // Get the pixels on the vector that crosses to the line vector
  990. pX = Math.floor( ( pixelX + crossVector.x * i ) );
  991. pY = Math.floor( ( pixelY + crossVector.y * i ) );
  992. // if pixel is over the rect. Continue
  993. if ( rectx1 >= pX || rectx2 <= pX || recty1 >= pY
  994. || recty2 <= pY )
  995. continue;
  996. // Find this pixel at which block
  997. var blockX = pX >> blockShift;
  998. var blockY = pY >> blockShift;
  999. var blockId = blockX + blockY * canvasWBlocks;
  1000. // Compare the pixel depth width z block.
  1001. if ( blockMaxZ[ blockId ] < minz ) continue;
  1002. blockMaxZ[ blockId ] = Math.min( blockMaxZ[ blockId ], maxz );
  1003. var bflags = blockFlags[ blockId ];
  1004. if ( bflags & BLOCK_NEEDCLEAR ) clearBlock( blockX, blockY );
  1005. blockFlags[ blockId ] = bflags & ~( BLOCK_ISCLEAR | BLOCK_NEEDCLEAR );
  1006. // draw pixel
  1007. var offset = pX + pY * canvasWidth;
  1008. if ( pZ < zbuffer[ offset ] ) {
  1009. shader( data, zbuffer, offset, pZ, color1, color2, material );
  1010. }
  1011. }
  1012. --length;
  1013. }
  1014. }
  1015. function clearBlock( blockX, blockY ) {
  1016. var zoffset = blockX * blockSize + blockY * blockSize * canvasWidth;
  1017. var poffset = zoffset * 4;
  1018. var zlinestep = canvasWidth - blockSize;
  1019. var plinestep = zlinestep * 4;
  1020. for ( var y = 0; y < blockSize; y ++ ) {
  1021. for ( var x = 0; x < blockSize; x ++ ) {
  1022. zbuffer[ zoffset ++ ] = maxZVal;
  1023. data[ poffset ++ ] = clearColor.r * 255 | 0;
  1024. data[ poffset ++ ] = clearColor.g * 255 | 0;
  1025. data[ poffset ++ ] = clearColor.b * 255 | 0;
  1026. data[ poffset ++ ] = alpha ? 0 : 255;
  1027. }
  1028. zoffset += zlinestep;
  1029. poffset += plinestep;
  1030. }
  1031. }
  1032. function finishClear( ) {
  1033. var block = 0;
  1034. for ( var y = 0; y < canvasHBlocks; y ++ ) {
  1035. for ( var x = 0; x < canvasWBlocks; x ++ ) {
  1036. if ( blockFlags[ block ] & BLOCK_NEEDCLEAR ) {
  1037. clearBlock( x, y );
  1038. blockFlags[ block ] = BLOCK_ISCLEAR;
  1039. }
  1040. block ++;
  1041. }
  1042. }
  1043. }
  1044. };
  1045. THREE.SoftwareRenderer.Texture = function() {
  1046. var canvas;
  1047. this.fromImage = function( image ) {
  1048. if ( ! image || image.width <= 0 || image.height <= 0 )
  1049. return;
  1050. if ( canvas === undefined ) {
  1051. canvas = document.createElement( 'canvas' );
  1052. }
  1053. var size = image.width > image.height ? image.width : image.height;
  1054. size = THREE.Math.nextPowerOfTwo( size );
  1055. if ( canvas.width != size || canvas.height != size ) {
  1056. canvas.width = size;
  1057. canvas.height = size;
  1058. }
  1059. var ctx = canvas.getContext( '2d' );
  1060. ctx.clearRect( 0, 0, size, size );
  1061. ctx.drawImage( image, 0, 0, size, size );
  1062. var imgData = ctx.getImageData( 0, 0, size, size );
  1063. this.data = imgData.data;
  1064. this.width = size;
  1065. this.height = size;
  1066. this.srcUrl = image.src;
  1067. };
  1068. };