PageRenderTime 115ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sandy/materials/BitmapMaterial.hx

http://github.com/sandy3d/sandy-hx
Haxe | 806 lines | 542 code | 116 blank | 148 comment | 99 complexity | 8f40812db6d204d9bf1233b9df890041 MD5 | raw file
  1. package sandy.materials;
  2. import flash.display.BitmapData;
  3. import flash.display.Graphics;
  4. import flash.display.Sprite;
  5. import flash.geom.ColorTransform;
  6. import flash.geom.Matrix;
  7. import flash.geom.Point;
  8. import sandy.core.Scene3D;
  9. import sandy.core.scenegraph.Shape3D;
  10. import sandy.core.data.Polygon;
  11. import sandy.core.data.Vertex;
  12. import sandy.core.data.UVCoord;
  13. import sandy.materials.attributes.MaterialAttributes;
  14. import sandy.util.NumberUtil;
  15. import sandy.HaxeTypes;
  16. #if js
  17. import Html5Dom;
  18. #end
  19. /**
  20. * Displays a bitmap on the faces of a 3D shape.
  21. *
  22. * @author Thomas Pfeiffer - kiroukou
  23. * @author Xavier Martin - zeflasher - transparency managment
  24. * @author Makc for first renderRect implementation
  25. * @author James Dahl - optimization in renderRec method
  26. * @author Niel Drummond - haXe port
  27. * @author Russell Weir - haXe port
  28. * @version 3.1
  29. * @date 26.07.2007
  30. */
  31. class BitmapMaterial extends Material, implements IAlphaMaterial
  32. {
  33. /**
  34. * This property enables smooth bitmap rendering when set to true.
  35. * The default value is set to false to have the best performance first.
  36. * Enable this property have a performance impact, use it warefully
  37. */
  38. public var smooth:Bool;
  39. /**
  40. * Precision of the bitmap mapping.
  41. * This material uses an affine linear mapping. It results in a lack of accuracy at rendering time when the surface to draw is too big.
  42. * One usual solution is to augment the number of polygon, but the performance cost can be quite big.
  43. * Another solution is to change the precision property value. The lower the value, the more accurate the perspective correction is.
  44. * To disable the perspective correction, set this property to zero, which is also the default value
  45. * If you use the precision to solve the distortion issue, you can reduce the primitives quality (except if you are experiencing some sorting issues)
  46. */
  47. public var precision:Int;
  48. /**
  49. * Maximum recurssion depth when using precision > 1 (which enables the perspective correction).
  50. * The bigger the number is, the more accurate the result will be.
  51. * Try to change this value to fits your needs to obtain the best performance.
  52. */
  53. public var maxRecurssionDepth:Int;
  54. #if js
  55. static inline var TEXTURED_FRAGMENT_SHADER:String = '
  56. #ifdef GL_ES
  57. precision highp float;
  58. #endif
  59. uniform sampler2D uSurface;
  60. varying vec2 vTexCoord;
  61. varying float vLightWeight;
  62. void main(void) {
  63. vec4 color = texture2D(uSurface, vec2(vTexCoord.s, vTexCoord.t));
  64. gl_FragColor = vec4(color.rgb * vLightWeight, color.a);
  65. }
  66. ';
  67. static inline var TEXTURED_VERTEX_SHADER:String = '
  68. attribute vec3 aVertPos;
  69. attribute vec3 aVertNorm;
  70. attribute vec2 aTexCoord;
  71. uniform mat4 uViewMatrix;
  72. uniform mat4 uProjMatrix;
  73. uniform mat4 uNormMatrix;
  74. uniform vec3 uLightDir;
  75. varying vec2 vTexCoord;
  76. varying float vLightWeight;
  77. void main(void) {
  78. // --
  79. vec4 viewPos = uViewMatrix * vec4(aVertPos, 1.0);
  80. gl_Position = uProjMatrix * viewPos;
  81. vTexCoord = aTexCoord;
  82. // --
  83. vec4 normal = uNormMatrix * vec4(aVertNorm, 1.0);
  84. vLightWeight = 1.0 + dot(normal.xyz, uLightDir);
  85. }
  86. ';
  87. static inline var SHADER_BUFFER_IDENTIFIERS = [ "aVertPos", "aVertNorm", "aTexCoord" ];
  88. static inline var SHADER_BUFFER_UNIFORMS = [ "uViewMatrix", "uProjMatrix", "uNormMatrix", "uLightDir" ];
  89. #end
  90. /**
  91. * Creates a new BitmapMaterial.
  92. * <p>Please note that we use internally a copy of the constructor bitmapdata. That means in case you need to access this bitmapdata, you can't just use the same reference
  93. * but you shall use the BitmapMaterial#texture getter property to make it work.</p>
  94. *
  95. * @param p_oTexture The bitmapdata for this material.
  96. * @param p_oAttr The attributes for this material.
  97. * @param p_nPrecision The precision of this material. Using a precision with 0 makes the material behave as before. Then 1 as precision is very high and requires a lot of computation but proceed a the best perpective mapping correction. Bigger values are less CPU intensive but also less accurate. Usually a value of 5 is enough.
  98. *
  99. * @see sandy.materials.attributes.MaterialAttributes
  100. */
  101. public function new( ?p_oTexture:BitmapData, ?p_oAttr:MaterialAttributes, p_nPrecision:Int = 0)
  102. {
  103. smooth = false;
  104. precision = 0;
  105. maxRecurssionDepth = 5;
  106. m_oDrawMatrix = new Matrix();
  107. m_oColorTransform = new ColorTransform();
  108. map = new Matrix();
  109. m_nAlpha = 1.0;
  110. m_nRecLevel = 0;
  111. m_oPoint = new Point();
  112. matrix = new Matrix();
  113. m_oTiling = new Point( 1, 1 );
  114. m_oOffset = new Point( 0, 0 );
  115. forceUpdate = false;
  116. #if (js && SANDY_WEBGL)
  117. if ( jeash.Lib.mOpenGL )
  118. {
  119. if (m_sFragmentShader == null )
  120. m_sFragmentShader = TEXTURED_FRAGMENT_SHADER;
  121. if (m_sVertexShader == null )
  122. m_sVertexShader = TEXTURED_VERTEX_SHADER;
  123. m_oShaderGL = Graphics.CreateShaderGL( m_sFragmentShader, m_sVertexShader, SHADER_BUFFER_IDENTIFIERS );
  124. }
  125. #end
  126. super(p_oAttr);
  127. // --
  128. m_oType = MaterialType.BITMAP;
  129. // --
  130. texture = p_oTexture;
  131. // var temp:BitmapData = new BitmapData( p_oTexture.width, p_oTexture.height, true, 0 );
  132. // temp.draw( p_oTexture );
  133. // texture = temp;
  134. // --
  135. m_oPolygonMatrixMap = new IntHash();
  136. precision = p_nPrecision;
  137. }
  138. /**
  139. * Renders this material on the face it dresses
  140. *
  141. * @param p_oScene The current scene
  142. * @param p_oPolygon The face to be rendered
  143. * @param p_mcContainer The container to draw on
  144. */
  145. public override function renderPolygon( p_oScene:Scene3D, p_oPolygon:Polygon, p_mcContainer:Sprite ):Void
  146. {
  147. if( m_oTexture == null ) return;
  148. // --
  149. var l_points:Array<Vertex>, l_uv:Array<UVCoord>;
  150. // --
  151. polygon = p_oPolygon;
  152. graphics = p_mcContainer.graphics;
  153. // --
  154. m_nRecLevel = 0;
  155. // --
  156. if( polygon.isClipped || polygon.vertices.length > 3 )
  157. {
  158. l_points = polygon.isClipped ? p_oPolygon.cvertices : p_oPolygon.vertices;
  159. l_uv = polygon.isClipped ? p_oPolygon.caUVCoord : p_oPolygon.aUVCoord;
  160. // --
  161. for( i in 1...l_points.length - 1)
  162. {
  163. map = _createTextureMatrix( l_uv[0].u, l_uv[0].v, l_uv[i].u, l_uv[i].v, l_uv[i+1].u, l_uv[i+1].v );
  164. // --
  165. var v0 = l_points[0];
  166. var v1 = l_points[i];
  167. var v2 = l_points[i+1];
  168. if( precision == 0 )
  169. {
  170. renderTriangle(map.a, map.b, map.c, map.d, map.tx, map.ty, v0.sx, v0.sy, v1.sx, v1.sy, v2.sx, v2.sy );
  171. }
  172. else
  173. {
  174. #if cpp
  175. renderRec( [map.a, map.b, map.c, map.d, map.tx, map.ty,
  176. v0.sx, v0.sy, v0.wz,
  177. v1.sx, v1.sy, v1.wz,
  178. v2.sx, v2.sy, v2.wz]);
  179. #else
  180. renderRec( map.a, map.b, map.c, map.d, map.tx, map.ty,
  181. v0.sx, v0.sy, v0.wz,
  182. v1.sx, v1.sy, v1.wz,
  183. v2.sx, v2.sy, v2.wz);
  184. #end
  185. }
  186. }
  187. }
  188. else
  189. {
  190. l_points = p_oPolygon.vertices;
  191. l_uv = p_oPolygon.aUVCoord;
  192. // --
  193. map = m_oPolygonMatrixMap.get(polygon.id);
  194. if(map != null) {
  195. var v0:Vertex = l_points[0];
  196. var v1:Vertex = l_points[1];
  197. var v2:Vertex = l_points[2];
  198. if( precision == 0 )
  199. {
  200. renderTriangle(map.a, map.b, map.c, map.d, map.tx, map.ty, v0.sx, v0.sy, v1.sx, v1.sy, v2.sx, v2.sy );
  201. }
  202. else
  203. {
  204. #if cpp
  205. renderRec( [map.a, map.b, map.c, map.d, map.tx, map.ty,
  206. v0.sx, v0.sy, v0.wz,
  207. v1.sx, v1.sy, v1.wz,
  208. v2.sx, v2.sy, v2.wz]);
  209. #else
  210. renderRec( map.a, map.b, map.c, map.d, map.tx, map.ty,
  211. v0.sx, v0.sy, v0.wz,
  212. v1.sx, v1.sy, v1.wz,
  213. v2.sx, v2.sy, v2.wz);
  214. #end
  215. }
  216. }
  217. }
  218. // --
  219. super.renderPolygon( p_oScene, p_oPolygon, p_mcContainer );
  220. // --
  221. l_points = null;
  222. l_uv = null;
  223. }
  224. #if cpp
  225. private function renderRec( args:Array<Float> ):Void
  226. {
  227. var ta:Float = args[0];
  228. var tb:Float = args[1];
  229. var tc:Float = args[2];
  230. var td:Float = args[3];
  231. var tx:Float = args[4];
  232. var ty:Float = args[5];
  233. var ax:Float = args[6];
  234. var ay:Float = args[7];
  235. var az:Float = args[8];
  236. var bx:Float = args[9];
  237. var by:Float = args[10];
  238. var bz:Float = args[11];
  239. var cx:Float = args[12];
  240. var cy:Float = args[13];
  241. var cz:Float = args[14];
  242. m_nRecLevel++;
  243. var ta2:Float = ta+ta;
  244. var tb2:Float = tb+tb;
  245. var tc2:Float = tc+tc;
  246. var td2:Float = td+td;
  247. var tx2:Float = tx+tx;
  248. var ty2:Float = ty+ty;
  249. var mabz:Float = 2 / (az + bz);
  250. var mbcz:Float = 2 / (bz + cz);
  251. var mcaz:Float = 2 / (cz + az);
  252. var mabx:Float = (ax*az + bx*bz)*mabz;
  253. var maby:Float = (ay*az + by*bz)*mabz;
  254. var mbcx:Float = (bx*bz + cx*cz)*mbcz;
  255. var mbcy:Float = (by*bz + cy*cz)*mbcz;
  256. var mcax:Float = (cx*cz + ax*az)*mcaz;
  257. var mcay:Float = (cy*cz + ay*az)*mcaz;
  258. var dabx:Float = ax + bx - mabx;
  259. var daby:Float = ay + by - maby;
  260. var dbcx:Float = bx + cx - mbcx;
  261. var dbcy:Float = by + cy - mbcy;
  262. var dcax:Float = cx + ax - mcax;
  263. var dcay:Float = cy + ay - mcay;
  264. var dsab:Float = (dabx*dabx + daby*daby);
  265. var dsbc:Float = (dbcx*dbcx + dbcy*dbcy);
  266. var dsca:Float = (dcax*dcax + dcay*dcay);
  267. var mabxHalf:Float = mabx*0.5;
  268. var mabyHalf:Float = maby*0.5;
  269. var azbzHalf:Float = (az+bz)*0.5;
  270. var mcaxHalf:Float = mcax*0.5;
  271. var mcayHalf:Float = mcay*0.5;
  272. var czazHalf:Float = (cz+az)*0.5;
  273. var mbcxHalf:Float = mbcx*0.5;
  274. var mbcyHalf:Float = mbcy*0.5;
  275. var bzczHalf:Float = (bz+cz)*0.5;
  276. if (( m_nRecLevel > maxRecurssionDepth ) || ((dsab <= precision) && (dsca <= precision) && (dsbc <= precision))){
  277. renderTriangle(ta, tb, tc, td, tx, ty, ax, ay, bx, by, cx, cy);
  278. m_nRecLevel--;
  279. } else if ((dsab > precision) && (dsca > precision) && (dsbc > precision) ){
  280. renderRec([ta2, tb2, tc2, td2, tx2, ty2,
  281. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, mcaxHalf, mcayHalf, czazHalf]);
  282. renderRec([ta2, tb2, tc2, td2, tx2-1, ty2,
  283. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf]);
  284. renderRec([ta2, tb2, tc2, td2, tx2, ty2-1,
  285. mcaxHalf, mcayHalf, czazHalf, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz]);
  286. renderRec([-ta2, -tb2, -tc2, -td2, -tx2+1, -ty2+1,
  287. mbcxHalf, mbcyHalf, bzczHalf, mcaxHalf, mcayHalf, czazHalf, mabxHalf, mabyHalf, azbzHalf]);
  288. m_nRecLevel--;
  289. } else {
  290. var dmax:Float = Math.max(dsab, Math.max(dsca, dsbc));
  291. if (dsab == dmax) {
  292. renderRec([ta2, tb, tc2, td, tx2, ty,
  293. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, cx, cy, cz]);
  294. renderRec([ta2+tb, tb, tc2+td, td, tx2+ty-1, ty,
  295. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, cx, cy, cz]);
  296. m_nRecLevel--;
  297. } else if (dsca == dmax){
  298. renderRec([ta, tb2, tc, td2, tx, ty2,
  299. ax, ay, az, bx, by, bz, mcaxHalf, mcayHalf, czazHalf]);
  300. renderRec([ta, tb2 + ta, tc, td2 + tc, tx, ty2+tx-1,
  301. mcaxHalf, mcayHalf, czazHalf, bx, by, bz, cx, cy, cz]);
  302. m_nRecLevel--;
  303. } else {
  304. renderRec([ta-tb, tb2, tc-td, td2, tx-ty, ty2,
  305. ax, ay, az, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf]);
  306. renderRec([ta2, tb-ta, tc2, td-tc, tx2, ty-tx,
  307. ax, ay, az, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz]);
  308. m_nRecLevel--;
  309. }
  310. }
  311. }
  312. #else
  313. private function renderRec( ta:Float, tb:Float, tc:Float, td:Float, tx:Float, ty:Float,
  314. ax:Float, ay:Float, az:Float, bx:Float, by:Float, bz:Float, cx:Float, cy:Float, cz:Float):Void
  315. {
  316. m_nRecLevel++;
  317. var ta2:Float = ta+ta;
  318. var tb2:Float = tb+tb;
  319. var tc2:Float = tc+tc;
  320. var td2:Float = td+td;
  321. var tx2:Float = tx+tx;
  322. var ty2:Float = ty+ty;
  323. var mabz:Float = 2 / (az + bz);
  324. var mbcz:Float = 2 / (bz + cz);
  325. var mcaz:Float = 2 / (cz + az);
  326. var mabx:Float = (ax*az + bx*bz)*mabz;
  327. var maby:Float = (ay*az + by*bz)*mabz;
  328. var mbcx:Float = (bx*bz + cx*cz)*mbcz;
  329. var mbcy:Float = (by*bz + cy*cz)*mbcz;
  330. var mcax:Float = (cx*cz + ax*az)*mcaz;
  331. var mcay:Float = (cy*cz + ay*az)*mcaz;
  332. var dabx:Float = ax + bx - mabx;
  333. var daby:Float = ay + by - maby;
  334. var dbcx:Float = bx + cx - mbcx;
  335. var dbcy:Float = by + cy - mbcy;
  336. var dcax:Float = cx + ax - mcax;
  337. var dcay:Float = cy + ay - mcay;
  338. var dsab:Float = (dabx*dabx + daby*daby);
  339. var dsbc:Float = (dbcx*dbcx + dbcy*dbcy);
  340. var dsca:Float = (dcax*dcax + dcay*dcay);
  341. var mabxHalf:Float = mabx*0.5;
  342. var mabyHalf:Float = maby*0.5;
  343. var azbzHalf:Float = (az+bz)*0.5;
  344. var mcaxHalf:Float = mcax*0.5;
  345. var mcayHalf:Float = mcay*0.5;
  346. var czazHalf:Float = (cz+az)*0.5;
  347. var mbcxHalf:Float = mbcx*0.5;
  348. var mbcyHalf:Float = mbcy*0.5;
  349. var bzczHalf:Float = (bz+cz)*0.5;
  350. if (( m_nRecLevel > maxRecurssionDepth ) || ((dsab <= precision) && (dsca <= precision) && (dsbc <= precision)))
  351. {
  352. renderTriangle(ta, tb, tc, td, tx, ty, ax, ay, bx, by, cx, cy);
  353. m_nRecLevel--; return;
  354. }
  355. if ((dsab > precision) && (dsca > precision) && (dsbc > precision) )
  356. {
  357. renderRec(ta2, tb2, tc2, td2, tx2, ty2,
  358. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, mcaxHalf, mcayHalf, czazHalf);
  359. renderRec(ta2, tb2, tc2, td2, tx2-1, ty2,
  360. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf);
  361. renderRec(ta2, tb2, tc2, td2, tx2, ty2-1,
  362. mcaxHalf, mcayHalf, czazHalf, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz);
  363. renderRec(-ta2, -tb2, -tc2, -td2, -tx2+1, -ty2+1,
  364. mbcxHalf, mbcyHalf, bzczHalf, mcaxHalf, mcayHalf, czazHalf, mabxHalf, mabyHalf, azbzHalf);
  365. m_nRecLevel--; return;
  366. }
  367. var dmax:Float = Math.max(dsab, Math.max(dsca, dsbc));
  368. if (dsab == dmax)
  369. {
  370. renderRec(ta2, tb, tc2, td, tx2, ty,
  371. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, cx, cy, cz);
  372. renderRec(ta2+tb, tb, tc2+td, td, tx2+ty-1, ty,
  373. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, cx, cy, cz);
  374. m_nRecLevel--; return;
  375. }
  376. if (dsca == dmax)
  377. {
  378. renderRec(ta, tb2, tc, td2, tx, ty2,
  379. ax, ay, az, bx, by, bz, mcaxHalf, mcayHalf, czazHalf);
  380. renderRec(ta, tb2 + ta, tc, td2 + tc, tx, ty2+tx-1,
  381. mcaxHalf, mcayHalf, czazHalf, bx, by, bz, cx, cy, cz);
  382. m_nRecLevel--; return;
  383. }
  384. renderRec(ta-tb, tb2, tc-td, td2, tx-ty, ty2,
  385. ax, ay, az, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf);
  386. renderRec(ta2, tb-ta, tc2, td-tc, tx2, ty-tx,
  387. ax, ay, az, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz);
  388. m_nRecLevel--;
  389. }
  390. #end
  391. private function renderTriangle(a:Float, b:Float, c:Float, d:Float, tx:Float, ty:Float,
  392. v0x:Float, v0y:Float, v1x:Float, v1y:Float, v2x:Float, v2y:Float):Void
  393. {
  394. var a2:Float = v1x - v0x;
  395. var b2:Float = v1y - v0y;
  396. var c2:Float = v2x - v0x;
  397. var d2:Float = v2y - v0y;
  398. matrix.a = a*a2 + b*c2;
  399. matrix.b = a*b2 + b*d2;
  400. matrix.c = c*a2 + d*c2;
  401. matrix.d = c*b2 + d*d2;
  402. matrix.tx = tx*a2 + ty*c2 + v0x;
  403. matrix.ty = tx*b2 + ty*d2 + v0y;
  404. // smooth threshold
  405. var st:Float = v0x*(d2 - b2) - v1x*d2 + v2x*b2; if (st < 0) st = -st;
  406. graphics.lineStyle();
  407. graphics.beginBitmapFill((m_nAlpha == 1) ? m_oTexture : m_oTextureClone, matrix, repeat, smooth && (st > 100));
  408. graphics.moveTo(v0x, v0y);
  409. graphics.lineTo(v1x, v1y);
  410. graphics.lineTo(v2x, v2y);
  411. graphics.endFill();
  412. }
  413. // private function _createTextureMatrix( p_aUv:Array<UVCoord> ):Matrix
  414. // {
  415. // var u0: Float = (p_aUv[0].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  416. // v0: Float = (p_aUv[0].v * m_oTiling.y + m_oOffset.y) * m_nHeight,
  417. // u1: Float = (p_aUv[1].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  418. // v1: Float = (p_aUv[1].v * m_oTiling.y + m_oOffset.y) * m_nHeight,
  419. // u2: Float = (p_aUv[2].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  420. // v2: Float = (p_aUv[2].v * m_oTiling.y + m_oOffset.y) * m_nHeight;
  421. // // -- Fix perpendicular projections. Not sure it is really useful here since there's no texture prjection. This will certainly solve the freeze problem tho
  422. // if( (u0 == u1 && v0 == v1) || (u0 == u2 && v0 == v2) )
  423. // {
  424. // u0 -= (u0 > 0.05)? 0.05 : -0.05;
  425. // v0 -= (v0 > 0.07)? 0.07 : -0.07;
  426. // }
  427. // if( u2 == u1 && v2 == v1 )
  428. // {
  429. // u2 -= (u2 > 0.05)? 0.04 : -0.04;
  430. // v2 -= (v2 > 0.06)? 0.06 : -0.06;
  431. // }
  432. // // --
  433. // var m:Matrix = new Matrix( (u1 - u0), (v1 - v0), (u2 - u0), (v2 - v0), u0, v0 );
  434. // m.invert();
  435. // return m;
  436. // }
  437. private function _createTextureMatrix( p_nU0:Float, p_nV0:Float, p_nU1:Float, p_nV1:Float, p_nU2:Float, p_nV2:Float ):Matrix
  438. {
  439. var u0: Float = (p_nU0 * m_oTiling.x + m_oOffset.x) * m_nWidth,
  440. v0: Float = (p_nV0 * m_oTiling.y + m_oOffset.y) * m_nHeight,
  441. u1: Float = (p_nU1 * m_oTiling.x + m_oOffset.x) * m_nWidth,
  442. v1: Float = (p_nV1 * m_oTiling.y + m_oOffset.y) * m_nHeight,
  443. u2: Float = (p_nU2 * m_oTiling.x + m_oOffset.x) * m_nWidth,
  444. v2: Float = (p_nV2 * m_oTiling.y + m_oOffset.y) * m_nHeight;
  445. // -- Fix perpendicular projections. Not sure it is really useful here since there's no texture prjection. This will certainly solve the freeze problem tho
  446. if( (u0 == u1 && v0 == v1) || (u0 == u2 && v0 == v2) )
  447. {
  448. u0 -= (u0 > 0.05)? 0.05 : -0.05;
  449. v0 -= (v0 > 0.07)? 0.07 : -0.07;
  450. }
  451. if( u2 == u1 && v2 == v1 )
  452. {
  453. u2 -= (u2 > 0.05)? 0.04 : -0.04;
  454. v2 -= (v2 > 0.06)? 0.06 : -0.06;
  455. }
  456. // --
  457. var m:Matrix = new Matrix( (u1 - u0), (v1 - v0), (u2 - u0), (v2 - v0), u0, v0 );
  458. m.invert();
  459. return m;
  460. }
  461. /**
  462. * The texture ( bitmap ) of this material.
  463. */
  464. public var texture(__getTexture,__setTexture):BitmapData;
  465. private function __getTexture():BitmapData
  466. {
  467. return m_oTexture;
  468. }
  469. /**
  470. * @private
  471. */
  472. private function __setTexture( p_oTexture:BitmapData ):BitmapData
  473. {
  474. if( p_oTexture == m_oTexture )
  475. {
  476. return p_oTexture;
  477. }
  478. else
  479. {
  480. if( m_oTexture != null ) m_oTexture.dispose();
  481. }
  482. // --
  483. var l_bReWrap:Bool = false;
  484. if( m_nHeight != p_oTexture.height) l_bReWrap = true;
  485. else if( m_nWidth != p_oTexture.width) l_bReWrap = true;
  486. // --
  487. m_oTexture = p_oTexture;
  488. m_nHeight = m_oTexture.height;
  489. m_nWidth = m_oTexture.width;
  490. m_nInvHeight = 1/m_nHeight;
  491. m_nInvWidth = 1/m_nWidth;
  492. // -- We reinitialize the precomputed matrix
  493. if( l_bReWrap && m_oPolygonMatrixMap != null )
  494. {
  495. for( l_sID in m_oPolygonMatrixMap.keys() )
  496. {
  497. var l_oPoly:Polygon = Polygon.POLYGON_MAP.get( l_sID );
  498. unlink( l_oPoly );
  499. init( l_oPoly );
  500. }
  501. }
  502. return p_oTexture;
  503. }
  504. /**
  505. * Sets texture tiling and optional offset. Tiling is applied first.
  506. */
  507. public function setTiling( p_nW:Float, p_nH:Float, p_nU:Float = 0.0, p_nV:Float = 0.0 ):Void
  508. {
  509. m_oTiling.x = p_nW;
  510. m_oTiling.y = p_nH;
  511. // --
  512. m_oOffset.x = p_nU - Math.floor (p_nU);
  513. m_oOffset.y = p_nV - Math.floor (p_nV);
  514. // --
  515. m_bModified = true;
  516. // is this necessary now?
  517. for( l_sID in m_oPolygonMatrixMap.keys() )
  518. {
  519. var l_oPoly:Polygon = Polygon.POLYGON_MAP.get( l_sID );
  520. unlink( l_oPoly );
  521. init( l_oPoly );
  522. }
  523. }
  524. /**
  525. * Changes the transparency of the texture.
  526. *
  527. * <p>The passed value is the percentage of opacity. Note that in order for this to work with animated texture,
  528. * you need set material transparency every time after new texture frame is rendered.</p>
  529. *
  530. * @param p_nValue A value between 0 and 1. (automatically constrained)
  531. */
  532. public function setTransparency( p_nValue:Float ):Void
  533. {
  534. if (m_oTexture == null)
  535. {
  536. throw "Setting transparency requires setting texture first.";
  537. }
  538. p_nValue = NumberUtil.constrain( p_nValue, 0, 1 ); m_nAlpha = p_nValue;
  539. if (p_nValue == 1) return;
  540. if (m_oTextureClone != null)
  541. {
  542. if ((m_oTextureClone.height != m_oTexture.height) ||
  543. (m_oTextureClone.width != m_oTexture.width))
  544. {
  545. m_oTextureClone.dispose ();
  546. m_oTextureClone = null;
  547. }
  548. }
  549. if (m_oTextureClone == null)
  550. {
  551. m_oTextureClone = new BitmapData (m_oTexture.width, m_oTexture.height, true, 0);
  552. }
  553. m_oColorTransform.alphaMultiplier = p_nValue;
  554. m_oTextureClone.lock ();
  555. m_oTextureClone.fillRect (m_oTextureClone.rect, #if neko cast #end 0 );
  556. m_oTextureClone.draw (m_oTexture, m_oDrawMatrix, m_oColorTransform);
  557. m_oTextureClone.unlock ();
  558. }
  559. private var m_oTextureClone:BitmapData;
  560. private var m_oDrawMatrix:Matrix;
  561. private var m_oColorTransform:ColorTransform;
  562. /**
  563. * Indicates the alpha transparency value of the material. Valid values are 0 (fully transparent) to 1 (fully opaque).
  564. *
  565. * @default 1.0
  566. */
  567. public var alpha(__getAlpha,__setAlpha):Float;
  568. private function __getAlpha():Float
  569. {
  570. return m_nAlpha;
  571. }
  572. private function __setAlpha(p_nValue:Float):Float
  573. {
  574. setTransparency(p_nValue);
  575. m_bModified = true;
  576. return p_nValue;
  577. }
  578. override public function dispose():Void
  579. {
  580. super.dispose();
  581. if( m_oTexture != null ) m_oTexture.dispose();
  582. m_oTexture = null;
  583. if( m_oTextureClone != null ) m_oTextureClone.dispose();
  584. m_oTextureClone = null;
  585. m_oPolygonMatrixMap = null;
  586. }
  587. public override function unlink( p_oPolygon:Polygon ):Void
  588. {
  589. if( m_oPolygonMatrixMap != null )
  590. {
  591. if( m_oPolygonMatrixMap.exists(p_oPolygon.id) )
  592. m_oPolygonMatrixMap.remove(p_oPolygon.id);
  593. }
  594. // --
  595. super.unlink( p_oPolygon );
  596. }
  597. /**
  598. * @param p_oPolygon The face dressed by this material
  599. */
  600. public override function init( p_oPolygon:Polygon ):Void
  601. {
  602. if( m_oPolygonMatrixMap != null && p_oPolygon.vertices.length >= 3 )
  603. {
  604. var m:Matrix = null;
  605. // --
  606. if( m_nWidth > 0 && m_nHeight > 0 )
  607. {
  608. var l_aUV:Array<UVCoord> = p_oPolygon.aUVCoord;
  609. if( l_aUV != null )
  610. {
  611. m = _createTextureMatrix( l_aUV[0].u, l_aUV[0].v, l_aUV[1].u, l_aUV[1].v, l_aUV[2].u, l_aUV[2].v );
  612. }
  613. }
  614. // --
  615. m_oPolygonMatrixMap.set(p_oPolygon.id, m);
  616. }
  617. // --
  618. super.init( p_oPolygon );
  619. }
  620. #if (js && SANDY_WEBGL)
  621. /**
  622. * @param p_oGraphics The graphics object that will draw this material
  623. */
  624. public override function initGL( p_oShape:Shape3D, p_oSprite:Sprite ):Void
  625. {
  626. p_oSprite.graphics.beginBitmapFill(m_oTexture);
  627. var gl : WebGLRenderingContext = jeash.Lib.canvas.getContext(jeash.Lib.context);
  628. for (key in SHADER_BUFFER_UNIFORMS)
  629. p_oShape.uniforms.set(key, gl.getUniformLocation( p_oSprite.graphics.mShaderGL, key ));
  630. }
  631. /**
  632. * Called every frame, sets GPU uniforms if associated with this material.
  633. *
  634. * @param p_oGraphics The graphics object that will draw this material
  635. */
  636. override public function setMatrixUniformsGL( p_oShape:Shape3D, p_oSprite:Sprite )
  637. {
  638. var gl : WebGLRenderingContext = jeash.Lib.canvas.getContext(jeash.Lib.context);
  639. // --
  640. // set projection matrix uniform
  641. var _c = p_oShape.scene.camera.projectionMatrix.clone();
  642. _c.transpose();
  643. gl.uniformMatrix4fv( p_oShape.uniforms.get("uProjMatrix"), false, _c.toArray() );
  644. // --
  645. // set view matrix uniform
  646. var _v = p_oShape.scene.camera.viewMatrix.clone();
  647. var _m = p_oShape.viewMatrix.clone();
  648. _v.multiply( _m );
  649. _v.transpose();
  650. gl.uniformMatrix4fv( p_oShape.uniforms.get("uViewMatrix"), false, _v.toArray() );
  651. // --
  652. // set normal uniform
  653. var _n = p_oShape.viewMatrix.clone();
  654. _n.inverse();
  655. _n.multiply( _m );
  656. _n.transpose();
  657. gl.uniformMatrix4fv( p_oShape.uniforms.get("uNormMatrix"), false, _n.toArray() );
  658. // --
  659. // set light direction
  660. var _d = p_oShape.scene.light.getDirectionPoint3D();
  661. gl.uniform3f( p_oShape.uniforms.get("uLightDir"), _d.x, _d.y, _d.z );
  662. return true;
  663. }
  664. #end
  665. /**
  666. * Returns a string representation of this object.
  667. *
  668. * @return The fully qualified name of this object.
  669. */
  670. public function toString():String
  671. {
  672. return 'sandy.materials.BitmapMaterial' ;
  673. }
  674. var polygon:Polygon;
  675. var graphics:Graphics;
  676. var map:Matrix;
  677. private var m_oTexture:BitmapData;
  678. private var m_nHeight:Float;
  679. private var m_nWidth:Float;
  680. private var m_nInvHeight:Float;
  681. private var m_nInvWidth:Float;
  682. private var m_nAlpha:Float;
  683. private var m_nRecLevel:Int;
  684. private var m_oPolygonMatrixMap:IntHash<Matrix>;
  685. private var m_oPoint:Point;
  686. private var matrix:Matrix;
  687. private var m_oTiling:Point;
  688. private var m_oOffset:Point;
  689. public var forceUpdate:Bool;
  690. }