SoftwareRenderer.js 37 KB

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