SoftwareRenderer.js 37 KB

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