PageRenderTime 4163ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 1ms

/sandy/haxe/tags/3.0.2/src/sandy/materials/BitmapMaterial.hx

http://sandy.googlecode.com/
Haxe | 533 lines | 355 code | 55 blank | 123 comment | 60 complexity | caa50c34b819857772ed4d57f61e64bb MD5 | raw file
  1. /*
  2. # ***** BEGIN LICENSE BLOCK *****
  3. Copyright the original author or authors.
  4. Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/MPL-1.1.html
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. # ***** END LICENSE BLOCK *****
  14. */
  15. package sandy.materials;
  16. import flash.display.BitmapData;
  17. import flash.display.Graphics;
  18. import flash.display.Sprite;
  19. #if flash9
  20. import flash.filters.ColorMatrixFilter;
  21. #end
  22. import flash.geom.Matrix;
  23. import flash.geom.Point;
  24. import flash.geom.Rectangle;
  25. import sandy.core.Scene3D;
  26. import sandy.core.data.Polygon;
  27. import sandy.core.data.Vertex;
  28. import sandy.core.data.UVCoord;
  29. import sandy.materials.attributes.MaterialAttributes;
  30. import sandy.util.NumberUtil;
  31. /**
  32. * Displays a bitmap on the faces of a 3D shape.
  33. *
  34. * @author Thomas Pfeiffer - kiroukou
  35. * @author Xavier Martin - zeflasher - transparency managment
  36. * @author Makc for first renderRect implementation
  37. * @author James Dahl - optimization in renderRec method
  38. * @author Niel Drummond - haXe port
  39. *
  40. */
  41. class BitmapMaterial extends Material, implements IAlphaMaterial
  42. {
  43. /**
  44. * This property enables smooth bitmap rendering when set to true.
  45. * The default value is set to false to have the best performance first.
  46. * Enable this property have a performance impact, use it warefully
  47. */
  48. public var smooth:Bool;
  49. /**
  50. * Precision of the bitmap mapping.
  51. * 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.
  52. * One usual solution is to augment the number of polygon, but the performance cost can be quite big.
  53. * Another solution is to change the precision property value. The lower the value, the more accurate the perspective correction is.
  54. * To disable the perspective correction, set this property to zero, which is also the default value
  55. * If you use the precision to solve the distortion issue, you can reduce the primitives quality (except if you are experiencing some sorting issues)
  56. */
  57. public var precision:Int;
  58. /**
  59. * Maximum recurssion depth when using precision > 1 (which enables the perspective correction).
  60. * The bigger the number is, the more accurate the result will be.
  61. * Try to change this value to fits your needs to obtain the best performance.
  62. */
  63. public var maxRecurssionDepth:Int;
  64. /**
  65. * Creates a new BitmapMaterial.
  66. * <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
  67. * but you shall use the BitmapMaterial#texture getter property to make it work.</p>
  68. *
  69. * @param p_oTexture The bitmapdata for this material.
  70. * @param p_oAttr The attributes for this material.
  71. * @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.
  72. *
  73. * @see sandy.materials.attributes.MaterialAttributes
  74. */
  75. public function new( ?p_oTexture:BitmapData, ?p_oAttr:MaterialAttributes, p_nPrecision:Int = 0)
  76. {
  77. smooth = false;
  78. precision = 0;
  79. maxRecurssionDepth = 5;
  80. map = new Matrix();
  81. m_nRecLevel = 0;
  82. m_oPoint = new Point();
  83. matrix = new Matrix();
  84. m_oTiling = new Point( 1, 1 );
  85. m_oOffset = new Point( 0, 0 );
  86. forceUpdate = false;
  87. m_nAlpha = 1.0;
  88. super(p_oAttr);
  89. // --
  90. m_oType = MaterialType.BITMAP;
  91. // --
  92. var temp:BitmapData = new BitmapData( p_oTexture.width, p_oTexture.height, true, 0 );
  93. temp.draw( p_oTexture );
  94. texture = temp;
  95. // --
  96. #if flash9
  97. m_oCmf = new ColorMatrixFilter();
  98. #end
  99. m_oPolygonMatrixMap = new Array();
  100. precision = p_nPrecision;
  101. }
  102. /**
  103. * Renders this material on the face it dresses
  104. *
  105. * @param p_oScene The current scene
  106. * @param p_oPolygon The face to be rendered
  107. * @param p_mcContainer The container to draw on
  108. */
  109. public override function renderPolygon( p_oScene:Scene3D, p_oPolygon:Polygon, p_mcContainer:Sprite ):Void
  110. {
  111. if( m_oTexture == null ) return;
  112. // --
  113. var l_points:Array<Vertex>, l_uv:Array<UVCoord>;
  114. // --
  115. polygon = p_oPolygon;
  116. graphics = p_mcContainer.graphics;
  117. // --
  118. m_nRecLevel = 0;
  119. // --
  120. if( polygon.isClipped )
  121. {
  122. l_points = p_oPolygon.cvertices.slice(0);
  123. l_uv = p_oPolygon.caUVCoord.slice(0);
  124. _tesselatePolygon( l_points, l_uv );
  125. }
  126. else if( polygon.vertices.length > 3 )
  127. {
  128. l_points = p_oPolygon.vertices.slice(0);
  129. l_uv = p_oPolygon.aUVCoord.slice(0);
  130. _tesselatePolygon( l_points, l_uv );
  131. }
  132. else
  133. {
  134. l_points = p_oPolygon.vertices;
  135. l_uv = p_oPolygon.aUVCoord;
  136. // --
  137. map = m_oPolygonMatrixMap[polygon.id];
  138. var v0:Vertex = l_points[0];
  139. var v1:Vertex = l_points[1];
  140. var v2:Vertex = l_points[2];
  141. if( precision == 0 )
  142. {
  143. 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 );
  144. }
  145. else
  146. {
  147. renderRec( map.a, map.b, map.c, map.d, map.tx, map.ty,
  148. v0.sx, v0.sy, v0.wz,
  149. v1.sx, v1.sy, v1.wz,
  150. v2.sx, v2.sy, v2.wz);
  151. }
  152. }
  153. // --
  154. if( attributes != null ) attributes.draw( graphics, polygon, this, p_oScene ) ;
  155. // --
  156. l_points = null;
  157. l_uv = null;
  158. }
  159. private function _tesselatePolygon ( p_aPoints:Array<Vertex>, p_aUv:Array<UVCoord> ):Void
  160. {
  161. var l_points: Array<Vertex> = p_aPoints.slice(0);
  162. var l_uv: Array<UVCoord> = p_aUv.slice(0);
  163. // --
  164. if( l_points.length > 3 )
  165. {
  166. l_points = l_points.slice( 0, 3 );
  167. l_uv = l_uv.slice( 0, 3 );
  168. // --
  169. p_aPoints.splice( 1, 1 );
  170. p_aUv.splice( 1, 1 );
  171. // --
  172. _tesselatePolygon( p_aPoints, p_aUv );
  173. }
  174. // --
  175. map = _createTextureMatrix( l_uv );
  176. // --
  177. var v0:Vertex = l_points[0];
  178. var v1:Vertex = l_points[1];
  179. var v2:Vertex = l_points[2];
  180. if( precision == 0 )
  181. {
  182. 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 );
  183. }
  184. else
  185. {
  186. renderRec( map.a, map.b, map.c, map.d, map.tx, map.ty,
  187. v0.sx, v0.sy, v0.wz,
  188. v1.sx, v1.sy, v1.wz,
  189. v2.sx, v2.sy, v2.wz);
  190. }
  191. // --
  192. l_points = null;
  193. l_uv = null;
  194. }
  195. private function renderRec( ta:Float, tb:Float, tc:Float, td:Float, tx:Float, ty:Float,
  196. ax:Float, ay:Float, az:Float, bx:Float, by:Float, bz:Float, cx:Float, cy:Float, cz:Float):Void
  197. {
  198. m_nRecLevel++;
  199. var ta2:Float = ta+ta;
  200. var tb2:Float = tb+tb;
  201. var tc2:Float = tc+tc;
  202. var td2:Float = td+td;
  203. var tx2:Float = tx+tx;
  204. var ty2:Float = ty+ty;
  205. var mabz:Float = 2 / (az + bz);
  206. var mbcz:Float = 2 / (bz + cz);
  207. var mcaz:Float = 2 / (cz + az);
  208. var mabx:Float = (ax*az + bx*bz)*mabz;
  209. var maby:Float = (ay*az + by*bz)*mabz;
  210. var mbcx:Float = (bx*bz + cx*cz)*mbcz;
  211. var mbcy:Float = (by*bz + cy*cz)*mbcz;
  212. var mcax:Float = (cx*cz + ax*az)*mcaz;
  213. var mcay:Float = (cy*cz + ay*az)*mcaz;
  214. var dabx:Float = ax + bx - mabx;
  215. var daby:Float = ay + by - maby;
  216. var dbcx:Float = bx + cx - mbcx;
  217. var dbcy:Float = by + cy - mbcy;
  218. var dcax:Float = cx + ax - mcax;
  219. var dcay:Float = cy + ay - mcay;
  220. var dsab:Float = (dabx*dabx + daby*daby);
  221. var dsbc:Float = (dbcx*dbcx + dbcy*dbcy);
  222. var dsca:Float = (dcax*dcax + dcay*dcay);
  223. var mabxHalf:Float = mabx*0.5;
  224. var mabyHalf:Float = maby*0.5;
  225. var azbzHalf:Float = (az+bz)*0.5;
  226. var mcaxHalf:Float = mcax*0.5;
  227. var mcayHalf:Float = mcay*0.5;
  228. var czazHalf:Float = (cz+az)*0.5;
  229. var mbcxHalf:Float = mbcx*0.5;
  230. var mbcyHalf:Float = mbcy*0.5;
  231. var bzczHalf:Float = (bz+cz)*0.5;
  232. if (( m_nRecLevel > maxRecurssionDepth ) || ((dsab <= precision) && (dsca <= precision) && (dsbc <= precision)))
  233. {
  234. renderTriangle(ta, tb, tc, td, tx, ty, ax, ay, bx, by, cx, cy);
  235. m_nRecLevel--; return;
  236. }
  237. if ((dsab > precision) && (dsca > precision) && (dsbc > precision) )
  238. {
  239. renderRec(ta2, tb2, tc2, td2, tx2, ty2,
  240. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, mcaxHalf, mcayHalf, czazHalf);
  241. renderRec(ta2, tb2, tc2, td2, tx2-1, ty2,
  242. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf);
  243. renderRec(ta2, tb2, tc2, td2, tx2, ty2-1,
  244. mcaxHalf, mcayHalf, czazHalf, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz);
  245. renderRec(-ta2, -tb2, -tc2, -td2, -tx2+1, -ty2+1,
  246. mbcxHalf, mbcyHalf, bzczHalf, mcaxHalf, mcayHalf, czazHalf, mabxHalf, mabyHalf, azbzHalf);
  247. m_nRecLevel--; return;
  248. }
  249. var dmax:Float = Math.max(dsab, Math.max(dsca, dsbc));
  250. if (dsab == dmax)
  251. {
  252. renderRec(ta2, tb, tc2, td, tx2, ty,
  253. ax, ay, az, mabxHalf, mabyHalf, azbzHalf, cx, cy, cz);
  254. renderRec(ta2+tb, tb, tc2+td, td, tx2+ty-1, ty,
  255. mabxHalf, mabyHalf, azbzHalf, bx, by, bz, cx, cy, cz);
  256. m_nRecLevel--; return;
  257. }
  258. if (dsca == dmax)
  259. {
  260. renderRec(ta, tb2, tc, td2, tx, ty2,
  261. ax, ay, az, bx, by, bz, mcaxHalf, mcayHalf, czazHalf);
  262. renderRec(ta, tb2 + ta, tc, td2 + tc, tx, ty2+tx-1,
  263. mcaxHalf, mcayHalf, czazHalf, bx, by, bz, cx, cy, cz);
  264. m_nRecLevel--; return;
  265. }
  266. renderRec(ta-tb, tb2, tc-td, td2, tx-ty, ty2,
  267. ax, ay, az, bx, by, bz, mbcxHalf, mbcyHalf, bzczHalf);
  268. renderRec(ta2, tb-ta, tc2, td-tc, tx2, ty-tx,
  269. ax, ay, az, mbcxHalf, mbcyHalf, bzczHalf, cx, cy, cz);
  270. m_nRecLevel--;
  271. }
  272. private function renderTriangle(a:Float, b:Float, c:Float, d:Float, tx:Float, ty:Float,
  273. v0x:Float, v0y:Float, v1x:Float, v1y:Float, v2x:Float, v2y:Float):Void
  274. {
  275. var a2:Float = v1x - v0x;
  276. var b2:Float = v1y - v0y;
  277. var c2:Float = v2x - v0x;
  278. var d2:Float = v2y - v0y;
  279. matrix.a = a*a2 + b*c2;
  280. matrix.b = a*b2 + b*d2;
  281. matrix.c = c*a2 + d*c2;
  282. matrix.d = c*b2 + d*d2;
  283. matrix.tx = tx*a2 + ty*c2 + v0x;
  284. matrix.ty = tx*b2 + ty*d2 + v0y;
  285. graphics.lineStyle();
  286. graphics.beginBitmapFill(m_oTexture, matrix, repeat, smooth);
  287. graphics.moveTo(v0x, v0y);
  288. graphics.lineTo(v1x, v1y);
  289. graphics.lineTo(v2x, v2y);
  290. graphics.endFill();
  291. }
  292. private function _createTextureMatrix( p_aUv:Array<UVCoord> ):Matrix
  293. {
  294. var u0: Float = (p_aUv[0].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  295. v0: Float = (p_aUv[0].v * m_oTiling.y + m_oOffset.y) * m_nHeight,
  296. u1: Float = (p_aUv[1].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  297. v1: Float = (p_aUv[1].v * m_oTiling.y + m_oOffset.y) * m_nHeight,
  298. u2: Float = (p_aUv[2].u * m_oTiling.x + m_oOffset.x) * m_nWidth,
  299. v2: Float = (p_aUv[2].v * m_oTiling.y + m_oOffset.y) * m_nHeight;
  300. // -- Fix perpendicular projections. Not sure it is really useful here since there's no texture prjection. This will certainly solve the freeze problem tho
  301. if( (u0 == u1 && v0 == v1) || (u0 == u2 && v0 == v2) )
  302. {
  303. u0 -= (u0 > 0.05)? 0.05 : -0.05;
  304. v0 -= (v0 > 0.07)? 0.07 : -0.07;
  305. }
  306. if( u2 == u1 && v2 == v1 )
  307. {
  308. u2 -= (u2 > 0.05)? 0.04 : -0.04;
  309. v2 -= (v2 > 0.06)? 0.06 : -0.06;
  310. }
  311. // --
  312. var m:Matrix = new Matrix( (u1 - u0), (v1 - v0), (u2 - u0), (v2 - v0), u0, v0 );
  313. m.invert();
  314. return m;
  315. }
  316. /**
  317. * The texture ( bitmap ) of this material.
  318. */
  319. public var texture(__getTexture,__setTexture):BitmapData;
  320. private function __getTexture():BitmapData
  321. {
  322. return m_oTexture;
  323. }
  324. /**
  325. * @private
  326. */
  327. private function __setTexture( p_oTexture:BitmapData ):BitmapData
  328. {
  329. if( p_oTexture == m_oTexture )
  330. {
  331. return null;
  332. }
  333. else
  334. {
  335. if( m_oTexture != null ) m_oTexture.dispose();
  336. if( m_orgTexture != null ) m_orgTexture.dispose();
  337. }
  338. // --
  339. var l_bReWrap:Bool = false;
  340. if( m_nHeight != p_oTexture.height) l_bReWrap = true;
  341. else if( m_nWidth != p_oTexture.width) l_bReWrap = true;
  342. // --
  343. m_oTexture = p_oTexture;
  344. m_orgTexture = p_oTexture.clone();
  345. m_nHeight = m_oTexture.height;
  346. m_nWidth = m_oTexture.width;
  347. m_nInvHeight = 1/m_nHeight;
  348. m_nInvWidth = 1/m_nWidth;
  349. // -- We reinitialize the precomputed matrix
  350. if( l_bReWrap && m_oPolygonMatrixMap != null )
  351. {
  352. for( l_sID in m_oPolygonMatrixMap )
  353. {
  354. //throw "Bad Transformation";
  355. //var l_oPoly:Polygon = Polygon.POLYGON_MAP.get( Std.int(l_sID) ) ;
  356. //init( l_oPoly );
  357. }
  358. }
  359. return p_oTexture;
  360. }
  361. /**
  362. * Sets texture tiling and optional offset. Tiling is applied first.
  363. */
  364. public function setTiling( p_nW:Float, p_nH:Float, p_nU:Float = 0.0, p_nV:Float = 0.0 ):Void
  365. {
  366. m_oTiling.x = p_nW;
  367. m_oTiling.y = p_nH;
  368. // --
  369. m_oOffset.x = p_nU - Math.floor (p_nU);
  370. m_oOffset.y = p_nV - Math.floor (p_nV);
  371. // --
  372. for( l_sID in m_oPolygonMatrixMap )
  373. {
  374. // FIXME: m_oPolygonMatrixMap cannot contain matrices and an integers at the same time.
  375. //var l_oPoly:Polygon = Polygon.POLYGON_MAP.get( Std.parseInt( l_sID ) );
  376. //init( l_oPoly );
  377. }
  378. }
  379. /**
  380. * Changes the transparency of the texture.
  381. *
  382. * <p>The passed value is the percentage of opacity.</p>
  383. *
  384. * @param p_nValue A value between 0 and 1. (automatically constrained)
  385. */
  386. public function setTransparency( p_nValue:Float ):Void
  387. {
  388. p_nValue = NumberUtil.constrain( p_nValue, 0, 1 );
  389. if( m_oCmf != null ) m_oCmf = null;
  390. var matrix:Array<Float> = [ 1, 0, 0, 0, 0,
  391. 0, 1, 0, 0, 0,
  392. 0, 0, 1, 0, 0,
  393. 0, 0, 0, p_nValue, 0];
  394. #if flash9
  395. m_oCmf = new ColorMatrixFilter( matrix );
  396. texture.applyFilter( m_orgTexture, texture.rect, m_oPoint, m_oCmf );
  397. #end
  398. }
  399. /**
  400. * Indicates the alpha transparency value of the material. Valid values are 0 (fully transparent) to 1 (fully opaque).
  401. *
  402. * @default 1.0
  403. */
  404. public var alpha(__getAlpha,__setAlpha):Float;
  405. private function __getAlpha():Float
  406. {
  407. return m_nAlpha;
  408. }
  409. private function __setAlpha(p_nValue:Float):Float
  410. {
  411. setTransparency(p_nValue);
  412. m_nAlpha = p_nValue;
  413. m_bModified = true;
  414. return p_nValue;
  415. }
  416. public override function unlink( p_oPolygon:Polygon ):Void
  417. {
  418. if( m_oPolygonMatrixMap[p_oPolygon.id] != null )
  419. m_oPolygonMatrixMap[p_oPolygon.id] = null;
  420. // --
  421. super.unlink( p_oPolygon );
  422. }
  423. /**
  424. * @param p_oPolygon The face dressed by this material
  425. */
  426. public override function init( p_oPolygon:Polygon ):Void
  427. {
  428. if( p_oPolygon.vertices.length >= 3 )
  429. {
  430. var m:Matrix = null;
  431. // --
  432. if( m_nWidth > 0 && m_nHeight > 0 )
  433. {
  434. var l_aUV:Array<UVCoord> = p_oPolygon.aUVCoord;
  435. if( l_aUV != null )
  436. {
  437. m = _createTextureMatrix( l_aUV );
  438. }
  439. }
  440. // --
  441. m_oPolygonMatrixMap[p_oPolygon.id] = m;
  442. }
  443. // --
  444. super.init( p_oPolygon );
  445. }
  446. /**
  447. * Returns a string representation of this object.
  448. *
  449. * @return The fully qualified name of this object.
  450. */
  451. public function toString():String
  452. {
  453. return 'sandy.materials.BitmapMaterial' ;
  454. }
  455. var polygon:Polygon;
  456. var graphics:Graphics;
  457. var map:Matrix;
  458. private var m_oTexture:BitmapData;
  459. private var m_orgTexture:BitmapData;
  460. private var m_nHeight:Float;
  461. private var m_nWidth:Float;
  462. private var m_nInvHeight:Float;
  463. private var m_nInvWidth:Float;
  464. private var m_nAlpha:Float;
  465. private var m_nRecLevel:Int;
  466. private var m_oPolygonMatrixMap:Array<Matrix>;
  467. private var m_oPoint:Point;
  468. #if flash9
  469. private var m_oCmf:ColorMatrixFilter;
  470. #else
  471. private var m_oCmf:Dynamic;
  472. #end
  473. private var matrix:Matrix;
  474. private var m_oTiling:Point;
  475. private var m_oOffset:Point;
  476. public var forceUpdate:Bool;
  477. }