From f0c86f20de9c74253ac2d5e4a075e34be1777cfa Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Sun, 20 Mar 2022 11:18:36 +0100 Subject: [PATCH] [DEV] proto of map editor for future gane ==> state we need to externalize it --- samples/resources/mapFactory/data/basic.frag | 17 ++ samples/resources/mapFactory/data/basic.vert | 21 +++ .../mapFactory/data/basicPalette.frag | 87 +++++++++ .../mapFactory/data/basicPalette.vert | 59 ++++++ samples/resources/mapFactory/data/clay.png | Bin 0 -> 15371 bytes .../resources/mapFactory/data/cube-one.obj | 46 +++++ .../resources/mapFactory/data/palette_1.json | 41 +++++ samples/src/module-info.java | 4 +- .../atriasoft/ege/mapFactory/ApplScene.java | 154 +++++++--------- .../atriasoft/ege/mapFactory/EgeScene.java | 53 ++++-- .../atriasoft/ege/mapFactory/Ground.java | 43 +++++ .../atriasoft/ege/mapFactory/MainWindows.java | 26 +++ .../ege/mapFactory/MapFactoryMain.java | 6 +- .../atriasoft/ege/mapFactory/model/Map.java | 12 ++ .../mapFactory/tools/MapToolInterface.java | 16 ++ .../ege/mapFactory/tools/ToolMapHeight.java | 120 ++++++++++++ .../atriasoft/ege/ControlCameraSimple.java | 33 ++-- src/org/atriasoft/ege/Environement.java | 1 - src/org/atriasoft/ege/camera/Camera.java | 30 +-- .../ege/camera/ProjectionInterface.java | 14 ++ .../ege/camera/ProjectionOrthogonal.java | 69 +++++++ .../ege/camera/ProjectionPerspective.java | 55 ++++++ .../atriasoft/ege/engines/EnginePhysics.java | 3 +- src/org/atriasoft/ege/geometry/Ray.java | 173 ++++++++++++++++-- .../math/ToolCollisionSphereWithTriangle.java | 26 +-- src/toolbox/Maths.java | 28 +++ 26 files changed, 971 insertions(+), 166 deletions(-) create mode 100644 samples/resources/mapFactory/data/basic.frag create mode 100644 samples/resources/mapFactory/data/basic.vert create mode 100644 samples/resources/mapFactory/data/basicPalette.frag create mode 100644 samples/resources/mapFactory/data/basicPalette.vert create mode 100644 samples/resources/mapFactory/data/clay.png create mode 100644 samples/resources/mapFactory/data/cube-one.obj create mode 100644 samples/resources/mapFactory/data/palette_1.json create mode 100644 samples/src/sample/atriasoft/ege/mapFactory/model/Map.java create mode 100644 samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java create mode 100644 samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java create mode 100644 src/org/atriasoft/ege/camera/ProjectionInterface.java create mode 100644 src/org/atriasoft/ege/camera/ProjectionOrthogonal.java create mode 100644 src/org/atriasoft/ege/camera/ProjectionPerspective.java diff --git a/samples/resources/mapFactory/data/basic.frag b/samples/resources/mapFactory/data/basic.frag new file mode 100644 index 0000000..13d2aa8 --- /dev/null +++ b/samples/resources/mapFactory/data/basic.frag @@ -0,0 +1,17 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +in vec2 io_textureCoords; + +uniform sampler2D in_textureBase; + +// output: +out vec4 out_Color; + +void main(void) { + out_Color = texture(in_textureBase, io_textureCoords); +} diff --git a/samples/resources/mapFactory/data/basic.vert b/samples/resources/mapFactory/data/basic.vert new file mode 100644 index 0000000..62bc6b6 --- /dev/null +++ b/samples/resources/mapFactory/data/basic.vert @@ -0,0 +1,21 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input: +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec2 in_textureCoords; +uniform mat4 in_matrixTransformation; +uniform mat4 in_matrixProjection; +uniform mat4 in_matrixView; + +// output: +out vec2 io_textureCoords; + +void main(void) { + gl_Position = in_matrixProjection * in_matrixView * in_matrixTransformation * vec4(in_position, 1.0); + io_textureCoords = in_textureCoords; +} diff --git a/samples/resources/mapFactory/data/basicPalette.frag b/samples/resources/mapFactory/data/basicPalette.frag new file mode 100644 index 0000000..3cd9d62 --- /dev/null +++ b/samples/resources/mapFactory/data/basicPalette.frag @@ -0,0 +1,87 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct Light { + vec3 color; + vec3 position; + vec3 attenuation; +}; + + +const int MAX_LIGHT_NUMBER = 8; + + +in vec2 io_textureCoords; +in vec3 io_surfaceNormal; +in vec3 io_toCameraVector; +in vec3 io_toLightVector[MAX_LIGHT_NUMBER]; +// FOW: Fog Of War result calculation +in float io_fowVisibility; + +// texture properties +uniform sampler2D in_textureBase; +// Material +//uniform Material in_material; +// 2 light for suns and other for locals ... +uniform Light in_lights[MAX_LIGHT_NUMBER]; +// global color of the sky ... needed to have a better color for the FOW +//uniform vec3 in_sky_color; +const vec3 in_sky_color = vec3(1.0,1.0,1.0); + +// output: +out vec4 out_Color; + +void main(void) { + // disable transparency elements in the texture ... + // Can be set at the start of the shader ... + /* + vec4 textureColour = texture(in_textureBase, io_textureCoords); + if (textureColour.a < 0.5) { + discard; + } + */ + //vec4 textureColour = vec4(1.0,1.0,1.0,1.0); + // keep material: + vec3 tex_ambientFactor = texture(in_textureBase, vec2(io_textureCoords.x, 4.5/8.0)).xyz; + //vec3 tex_diffuseFactor = texture(in_textureBase, vec2(io_textureCoords.x, 0.5/8.0)).xyz; + //vec4 textureColour = texture(in_textureBase, vec2(io_textureCoords.x, 0.5/8.0)); + vec4 textureColour = texture(in_textureBase, io_textureCoords); + vec3 tex_specularFactor = texture(in_textureBase, vec2(io_textureCoords.x, 2.5/8.0)).xyz; + float tex_shininess = texture(in_textureBase, vec2(io_textureCoords.x, 6.5/8.0)).x; + + vec3 unitNormal = normalize(io_surfaceNormal); + vec3 unitVectorToCamera = normalize(io_toCameraVector); + vec3 totalDiffuse = vec3(0.0); + vec3 totalSpecular = vec3(0.0); + for(int iii=0; iii maybe set an uniform for this + //totalDiffuse = max(totalDiffuse, 1.0); + //totalDiffuse = min(totalDiffuse, 0.4); + + //////out_Color = vec4(totalDiffuse,1.0) * textureColour + vec4(totalSpecular, 1.0); + out_Color = (vec4(totalDiffuse,1.0)*0.5+0.5) * textureColour; + /////out_Color = mix(vec4(in_sky_color,1.0), out_Color, io_fowVisibility); +} + + + + diff --git a/samples/resources/mapFactory/data/basicPalette.vert b/samples/resources/mapFactory/data/basicPalette.vert new file mode 100644 index 0000000..a707aa7 --- /dev/null +++ b/samples/resources/mapFactory/data/basicPalette.vert @@ -0,0 +1,59 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct Light { + vec3 color; + vec3 position; + vec3 attenuation; +}; +const int MAX_LIGHT_NUMBER = 8; + +// Input: +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec2 in_textureCoords; +layout (location = 2) in vec3 in_normal; +// 2 light for suns and other for locals ... +uniform Light in_lights[MAX_LIGHT_NUMBER]; + +uniform mat4 in_matrixTransformation; +uniform mat4 in_matrixProjection; +uniform mat4 in_matrixView; + +//uniform float in_numberOfRows; +//uniform vec2 in_offset; +const float in_numberOfRows = 1; +const vec2 in_offset = vec2(0.0,0.0); + +// Configuration of the FOV ==> TODO: Set it in parameter uniform ... +const float c_density = 0.007; +const float c_gradient = 1.5; + +// output: +out vec2 io_textureCoords; +out vec3 io_surfaceNormal; +out vec3 io_toCameraVector; +out vec3 io_toLightVector[MAX_LIGHT_NUMBER]; +// FOW: Fog Of War result calculation +out float io_fowVisibility; + +void main(void) { + vec4 worldPosition = in_matrixTransformation * vec4(in_position, 1.0); + vec4 positionRelativeToCam = in_matrixView * worldPosition; + gl_Position = in_matrixProjection * positionRelativeToCam; + io_textureCoords = (in_textureCoords/in_numberOfRows) + in_offset; + + io_surfaceNormal = (in_matrixTransformation * vec4(in_normal, 0.0)).xyz; + for(int iii=0;iii;5n}l2xn&%s;U40C?%k^ z9R0nN;#u!a1X$~_SafjC0|0yoaLxe$%Cf-Od#!g07X&c&!e@% zzw;GBK-U@c#+>{!S}XpLeP^&-wvbXlYYn9o6oBC)d+*`AM^%>N%>f_<@b2AN-Yfuc zoLJNQ5_c4GvSYkZ~{CJMLyB5o3 z2PGwfQV8C|IfuvP3T07%h&INoC5l2L_^`cKC;igCH;_^u+XWzc2q6F|)w4b6Q@o;- z0;|;;MC<`}Hb3rDRhAGF7Oc15v92mO=RhIA#S@?0;M6BLJDWiWfGD8rfx1?s6PJvj z?L5j-LTiDStP2}sz~yC)<+1|+R9d4A0fGn=0<3c=v<4AitOE>T89Ee&hLVDfy-@kO z*f9vfpIbMMc9zV@e2>AHlMWI0yUfI0^N(-d3qLct2@UU1R5Px1{?Pj0Sv&CyE z{W%ful@Jm_L<1Na4TZq2RZ0jU5TYTZ6CegIS;s{lZg#tNXl8oH2uJ|N1{i}^F@zBK zo;AiH2)6L9?;!vL@8Jb+w1^*8E5XJQ0BarEmY|g6t4>L1ts#T}5y4sqYdySo5K`i) zQHxR%uN8{$b4n;JcufT$AYiS<-CYZ%WjthIRRvIi&6?$6HpX#`%v-c+cE?p#53+ZHtn)h zFvjM0ud6B>fpxrja_jw*LGWe+)_GX#K-3SeBwkc0pMH-AN(bZR79gZRQ_FbQZj9^x zu7$NWZ$9Gbmr|lo3R>&IriXYv5H2rkl!b=U0##Mx>Z*aRDvkf~w_7|cT73V$2IAd0 z+?crD5JYg^Ln#&SSULHiVQ}wH#8e|gc+MR_(dCt8fe_m04*4}}8uZ2>cn@O?%Cg)s zf_(<@;$TcEfI{{pFS+J)%Aja)-z$MHUmml|PKS2g_o#{@8*JKqia)57#O>`F076yq z6-_Bv6#_8Ep{Yvz^)D5S@%Z|61#4Y4gg}I{EMbg+8eIeXACv+eO#7a_++yR1loF6i z?xaG6*0Av^IK>EFD-w74)cI#WArVm35<_2{VyrKpSCDe-HH|T7wz9Ic`Q8PbpVyer zD<}mBv3oUbR!RJ*Q_ifh0nX72cKdkVTb6n@@@zp8U)d4SF_Hqs^BR=sJgQ-&c@Ij;>r!G|I|0Mno|!KgWDtK}ziP zaB|XeLV!{NpFUmSHPK7(@}_xCF_bq(j-lL8$n0q+Uk`vIs#gWt4qe_AVOecJH} z#MUmPmn_^XUFSS6 z-YH0$k^+5ib5OVs#??w?&*i;`i>Z=`nT`+wO3G2n^wcNli~$kFoLe$dsT2T41*H@a zQb29+A|yMJfO0h=`yoZPE^`HR+ zzX`bb-ytr%gtZpUta=&Dx))auIcGg|(?}^`t%p*Fjio3{*!6mYWen2YwBgPSi&KrAb?ZP`28VbCO!n5pI3bC(AaAU!Ref}0VZyG*BMA9p`SOO_%MC6gp}yp7JY9}mBouej}Z92Qxa_TG15N-rV#;cYfdUI zxtJsG3nVp%$b(HH*a51hgn)>KA(YBTI1r)l`_X&*5Fn+5=`Ez3A$a2FkrLhonBKw| zhrW05^z*|Og+8r#6G1w}SnBF}7E#TOJ8D~xrdB7NO?}9%g+P<8l|q103SDQp@FHYB zh0cWxVu%B$h5|24St=+cHg0@~WQyHQXDC;~T94(j2aW`z);ajCUwtkevUb)7??0MmOI%T?C2;m5qzu}~uf!u$6Z z5Q28lSQ0?ndCX?&DB7xDa&tRp(RUKp*Ymu9RV8C^#+yvUo zL6vWa)NNu4&X&KqL-Y-l^_VN(oOiDv+ej4}tK@FE=}x%)XP^t_*@8 z7{fL9$Hh7t{WwaOQo>marPQ;aYXzO~1t~Ff5NtgnFadM9EW%aQCcD!69<=NHCSE5%XV6 zx=!moK*Vk~Qq?dK06OpCVmWw|OHz*ZfBflXo6o7I2MrgMfZz#rQ=plZxW8MWDoT(T zyK@%_E6)4u>C)%SUWy1!U2oP;@Grf+J)hkCZOGkut|Ce)Al0-naPUqjOU`EX_FuN$ z^yY^^BVZwsA1Q832*lBUjJmZ}P+De`EAaz_5NH~mQL47(SfKA6y3T?~KuTm3jZ*Fl z06G?@gcuhwh_LQ^25*Kz1hK^zy2MXEUp;&C1(@GxZP;x%`DeFkGJ?(f&Rnktoo zi+F+9S9&Ij!Rdy!mfZg0@wD24h?$J@1nPmJ5YWX09xT`hq!b$iAOiY54=9zu*RM;+ z324cC!p#kX5p`YUfP_LoI_MOQBj?~^Q-+$)DhSD*Knj3};oY_~2n3id!$=-uM12zi z^Vtl+GbvKUza$U}t?~0OSCawXshe+X;8gac0uQH_A3t8;{-J|476<`lSu#oG7&I66 zg4eUca(UY3@5W}lH`e+|LogC!0Pj5J^9sher{f2X2`H!L{6rk>_I-$P2N#Q!5)cp=nP>NJ@utWfZ<*5l@8hUe0Nw0b(K(RKR)6s?Xklv9h_YSjbS?In15 z(TUJ?%zPGmQ{L!xA{F{? z$Ac$RN{Qe-l$59&E~>o5L1`@ptl+~7YfLy=?$m{3`q+VeHP)i8D*WRg-*9_7M_H9H zy@S%?DD`Y~P0)B}``!U0j(QKKrhCk0I#S>_Z=|HmO}OcMi-KF+LnPH~m_GyV!GL_@ zU81Qa<`g%W9CMBO?rwcFI`#vi>xHrhrW8782;&@U)gP!39dKxU#zGa8gV)lM-FuGwl3G zAQGr51+5jTN^>h*tRiwzZS!oCB+{+tN#%P1Lf1Q3e5i+BF9rBwsBcI+7h05NDC_uk{~eu??42Eg_B)TE&#ux{PR^CWzo0>K74>38lw z1QN#BT=}H!>%!U0`n8TB_SL!v1&(E^N<%3bRY(LE$cAq;*lZ~TjIprRqwgJ@5Aco~ ze}oXn89_pb?4F8(rBa^LNXf;f)1cM9cMvCpWU0bPgrg)&iUJNH8bMi>P?DL&yr=~z z#QZq6!o5Kb#zsUmqPkYL0YwW%3g1bsveh8zSnl z2AiF~^&w#0wwcwUmExXrrBG;gJ^%Ri8@_ydWa{^klfuZ~iA9wI>E15XE3;sNG4AMz zrL7edLclx6cWz8?m&=wbcS^m=hEqiMw3euA1sNlE>%!#c)dLZZb=Sc-2b@4FOI|`o z;tO*QP7KHafP{dvHuvsvtC5aUC*!+LX$@m67K;|ERgb^^a(fsDcLX{y$3E5d6Od`; zQcA4bNf>MKfBx@3@Z+Z| zTwTs%2QY1+hNoo=L_qN3sKJL2nJzk=7J{?ksH?O4>hJ?Y2qB>DIuu%?ZTpxRFvY5_ zi^yUU8}$>ysN;CdgriYVrj*2D(dBNYsnWaKHqrG zoB?n;IP6y_OAUY^1ot{5We>Fn(?~>-sn3->sP!Jj#PuX%Tyt=JWB+}6uRg{bdILW) z*Zt~h7E?Z#Po{H(`MkpAMT5^@mRPNN=KD#Bx~gEkhqDg<*Z=+vmltQKn~g|RT@}z8 z@Q%BHhT1_PqGAcDE3_Eh*HVhnf~9ERT8GuDkIfO{uwRZ$o8id{Az;=tlSY}Aw<=3e z2&{^--Q*#+5Yk-8F?q|Dt8V9WABvZf$kVK8a-RW_00corFk*Y_L(Cw^dxQ}93Qz3f zscUyC?hpWUQR35w3r5svILO#_PI@C5u#TwcofF!zm5s8|; zF(`|IbqTi&XSYx(29?Ou>LVdCnRp`!Km2f!>D#9FXglUcIv+M(SYQ(*Dg{|pIgU#i z+_CN?{r>$WF3u~aXB~0VS#(HB{N*N{_1cW$35vM3kWWa{gvi0&&;r$ zPqbHb@%hCXUMqwE?*l%3xZt+080j`Mg=SVlD*@*N+O^FF!5v9#5Mj^<5zHXZ06`Agqxc=nnpv)5?5Ce!?pTXLI zKmJ%SU=)oYZGex`vs}I7`!tIirB2&7sC`dq=BB`v^>l!Xi!uvR2mt5j6>e^3czkSe zf6v0yN^`?%x>u{RL?Fr;LwcU)vUp?v2c(p^x^D6{cnq3ngAka{E1aKIfDln-#KkUZ z);Ly5qAE)k*R~c3L6dle=1_|0ofHzk{Bn(lhYsJrFHsg6v${qbJ9Uz4@*%**J2l;Z z>AnonKr(KSx@HoWZcChM--1g3owd8JcJMhsgq!OI)@%qW>54PPp(;!K^ized^H{CA zo$Eoy7A|89;5`SLO6A~jTeI)j8anUr%cmPqcsgBzh~Q%}pwJRUQRULR^T3xck8sYj zd|qTE3n9_<7O$6B3PSKK7k_zC;rBlt;hbab;RGoU+}%)rH&D);VWU*bJ|vF@N%v49 zO%7B+ZE~Mm_q0k1q4C6BUe?_0v*&r7BNSTT>S~6os~MI{z8<*lAV$}nh`>!7**z(q zN@5a2Xf%D!Y|uowy}5{}2EF(|4zG;lp@04L9ze)CPf{}XQ@^U)jsFY*`1I)ledqA| z9}8|1E9IzbXK1}d9QDhn8K9K{(!h#lv=8+gL=*yq^NV_P`cGNVv$F~p z7d6&vgRkFKK%iKaE8(nVc2e?O15XpSkgW7MXH6Z&G$k%BN|w}XSyWrT5-~7U39qjk zJUq0}N@e*Q@5AdF!1!7S&|2Ydf4jlAZ!5H|8OgYAf)U`yPd8cUKnMXJh}*m(Nd*xFw)5PD?Gz0B8J+j|;fD)Y%hkLjrGtT} zgG$}Ll3V1S+ce@m;fIeG`1RNCn|RCzXlp&nLgB625eVGi`NI#F`22Yh$%(OlFXrT? zcd=6iXqu>JyG6zFe&aEOP^c>2*x9Vg4I|F6aTw##^-QWrf(;^90DV6F&yCjCYc@71 zHbX4t^AhLh723|?anW%pHdax$r+5@vBM{;Iyhc^24E_u$4XHCJByuSwh?(OCDJH6% zN2;=)KQA)lJ7r}uwG+Siuy1{B|7BS!oS)aRg2Fm?sa(2R_p###=(~UAz^P5-Exvnq9`ks)!N7&U#pUcEk#cXjmH1S)o!{Fi>ph_?H9mg4 zKv8a#)T^@0oj@t(5fZq%ZV(8#yEkZCht-O|)@v7amf0{U9s&_nKKkBc-Fg@sV%~oo zX?G~)m1u(@dt4AF# z9Veq;w-^ngQLK=eKNI&YR;7lFTn6vB`SPg}G}iIN6Yq~Nc3O|ii}`3ONfOgYg_(D^ zb5H>8?>Z>Caq~%2U_&S84ewfq)Www!O9+JC1g6;$?PVkj0dDUf@C{P&NG4`Y+xe4> zAOz;VuU2e@UGMXTkG?#iHy*w5FeboSexM(Jyv!$1X>L-`N@cg{9354-+(*7h|C5Yh zHZNl;r@3NAg!x(dq|=}J7@sQm6+*z}iOXz6*WHB9R8o^ni3#Fp^HLomiZTNlv| zCX+BvQbfZS_s6lMH5&qdAP&A)lZp6YULh& zrAZ{oAd0Aj;e5dPMV;NvYSqK}kXy8T?6FJn&}$gHlzf$m!Eme)0xqu_6lIa4Rw-qi z*eaiOm{Ki6Wv(J$w%_ko*k{7Qd#=SK3Vhd@7pYf2_oWoq0Gg)E55$`H1m|{7cxt_F zJ0EKf<1ZIa^SbqDJHILP5HM@Xj4vo9@b%jYx{z-+;?-Ij)E)ruHq%7rvvM?8Qb>u_ zYW-v*AYw05RT4!Z;{XhSKmJ&7=5rt}NhDaA+L8C_{6tvN=iHuNd@@pMwO%`{Ru&YH zsZ2#7v3Oj=MbO1MPH&tibZv=v1g*qDbk5`PvET3pUK{<~3eu7` zLBc48Wo;304P)#{o|r)JfzUJ>@7~qe2u=um`Lf#Y`lH7gHloTj;Gpexe|ZRmcJ1@# zd(Xf_Z$hkMo$jmhrbh%Tas3zq4x2tX0#@rjMzU$v5KU6fpSmk`UFNBtLI~X5tx-3{ z>qR*6^LDMrL<>UJ8k}mb<@o|VLI47VJzpFxou5_s;o}_hc>$#q%2GpXh5HAC^}0X! zJbsHktcjb*(RU8#XH9lZQUbl%-DDAW$y$Q3tbC#L{?_soWQn~Z3VLX%GW8cBBmQa;)D;yr5&UW2l zx|N1j+|k7yf0U9WxAKw>uV_wVFH|4;w`8;nUrK~yUU$xWdj-g75Z zdWbachCdUZ-i+x>@uo^{Z#C{VOfaP+N60?v&O2x&o;TF_iLbJhIr<%*Ae|`80Icyl zLCZ@s5YR?yB?V(zYy9i?1L$z5E25MCZFa zgowwxx7R5IH+Y7y+Y_jyL?0f;)YEdqI6M^%fM@G@!6ciJue;d=bIAs)S z0Fe(lhZxUT*vpiTnh)F8rA{m0yhmLYSg#H0x_DCqDB_GrVvI#q zl>pvWLRCtMfBy3xKYY5x^3lA_-bXIuXfoN6AIPQdp(h-i2Ey2bN~JbEG|^B90PX3H z)}!c<3i#k4W%Vjj<@z-Zs8>_HFzlKbd%9Pjc5eozqVTIWX0wzHEdqSiXMGNr+f z7iEb+;gwzS&U6I)`S}qS=ksxY|7%@)O2nAwHR~xM2aJc5O%h$+Y)RFRmY>I+i40Y~ zrV|iSps6>fSSyLgMYp$BowW5+hpRCbZ~aQc9hb}XtL_rTYmZB{@}SJ#)IB|wPqL1H zLQ~g}A}OakSm$Ak%U=xjbH5;SCF+qT#x0U6-R)d7j={itOG4qxV}Em08c9RxJcU)Pd%0s zkgFtuBZ8I^ZQDaC;B3wi`L_EOVhq|&It{^ny2e^87TpdRh4())l^gf5iN(LZMkXlPI972;K*HkE1H4sX@qlIepfI zfH4L|Rj~lo%Ajj~l!MXPI}s7eQjOd-kGmHm4?sj%JaoAoOFVh+iTev;5Nxc+^)>Iy z5Fkt1NpefMO@NC~&V|fae*gXgkBbgnXQD)m52Gdq=N&3l;&IVKX@|2jc7?pi-20ah zzl5>NO76IRY#Brdz}?+4wp`2Or+>?W`@YAluCZDg1nRPKrY;n;k|;}!y4LxK^OZw` zo(!guKRmSPIx}ie-Tqx|-=mH*5s7#L8VfXTT*!Kj9TAIBx|=9q@dKQ)`3VF|r@n}) zB+2`}|8T)AqyzS|)&g}U0ZdMa+kvXR3z*MK7NCCr{(QhtrQAo}#oqo}l(@TF!ux=_ zu22*bRaJ}(B5m&8j711MK6Yr=CTj~FOwabbks!jl>!Ql1%*vU@I2dAGo{gTb%(ALH zE=FLrVu=~0vHvr~D@RC)w(l{IvMp0GFvmnJ4%I65B6Uf+MhG;qd4{zE1U`JaWY*JQ z;|nc82T+ng6epeTdcv~Q&`JsX^wSkSe_q7qL;)3>7>qG!`#!r{?>$0b-P&--AaZ}7 zz~ZsTdeuYe(=>fdbd@+@1jZN^t&FlNDSlBx1r zg`3_OiGqz<3Q1=mHJi?w3TJ2B%FYcnA`gM4BhdGHJw2X>b&vDdIM$_keC+Z4`zlWS z6#2fkF@G$yX33GLNa?+Y_io1^>bgYNTP&A7q{PXzt5lOXmaB>Qy~bKr9EtKXyOH!p zWB1fNaHJ>}4X%#{_m(f4GzNf;ZZPre!Lraiw7S@cOCPgG<_k_UgRDz}(Gt4rJhT=l zOD>Z(jmB^PeBe8^V0m(5OqPrHu~Ib*Gn5n~gIKS72qE`QA2}7B8>WO}>mJLE7DVvY zBE&(0d#-Jn5k2Mz2Ec(B0x_cOeEcb1X2 zB$Jlha@Tc7wFOUE{M5q_A<#4pwC0Xp?>t{SsY}){R>8`h8a81RY4Er?dS!8U{w^Xl@z~1R7ayhWk_osXCPA)!oZV?QfVBob5mo0r(5py zzIQTxKv_!EwZ@M>Ug6I_A3y|_hIKCAi7#QVq;!*O11bwANWl`b325P&!DWo*qo8F> zjn=Kf^d^-@G{ z!(Nck)FlY4EquxmV|3N$j-y= zULXabT?-wRoj&m=Q{rVDQ1_*U{6ZAws;n5h1u*HfBdmPQ=NN{i9h)QgK|@0j=5Ol?G+54_IKDqLUB zuvoPC{(TK8GX0Uw`|)17g(`<1bT%t*2(WVj}h1n+2rBR#HGm^1|0| ztHXmECx8d{JxJn(T8PYCfMLQ3*nNl@yL=aW;xOjX6xZ}{{dDrS@svwq$Z@V$SV zQ_aJ#zJIz_kCY0F1!DvCkPS0f;Ib%St;hR!=V)7x<P3J=HZNMo8kkW^$R#}1T+mX|c2);Zg1=LD`Ldf@il409BDlPt_?@w=93B&-C zi<*E*#Cg^<&=E5TffY@;|tHl3#Poj6-*rqJXy%9UHe$`f10p`%)gA{Tssmd zOO55ShdFZkQ}r%~np0l~?rJF{X0vi5)Zo~H_cf-ZtDud8nz>ARxEjXHBe@fQ6a#s8 z=Lpx=b1W8yhf&9fe@cw$b@p69DT#mm>mf_xjLWp@WD6kBvpnNY5Lnk5MZx9UfBtLD zT7btoO~Xb?WvKg?jEbT#a?1I4NFIZ6y=G9kqR3#Gsv;&&z=)U6si9U9l4){zprwG= z%REZ+kckLY#iQl7NgJ#z`nnWx5vP~`_S@Zt^0u|1r}76wFvjU4pgMa>O zwNaTm$;EQ?&cRkOT0p@S4JfcurgJWm6E?7`=^X?pO2dt(ggZ}AYX4#k!K!2oiTP6$ ztUA70o4uQtJeT(#P1Edc!!jnInH@io)^fmkC`}dMdB^|!=Y4#xU3Z;WPNz&)pCWoZ z*#L+F{`sPB?_m!ku5ZxRRA&F4P_%o>(QYh}lON^cE#j-Y_t`!bpI74Gd zi{V^=l7bmXYMS@ADeuaI0hg3GX)a-kPs(CHHA^aq&!1PL**?RJDE00o<2YVHeMzRk z{h9jyzJ1cD(Wy5A2-bR>ozVH#Y+LOR-!m?x(T{Cye9%171g3(O#&L7eBS)NHxq83N5!VO zN+$_f3)UTas{1D*l$C~e9uE)e*c|%A%}+xVoF_E3#`$@T`K*e>38qVHA(+V`B6&1Q zr2P8pJ){&UwT7_{kE<3p#l_y$Kr&m{3}(M`9hZ%q=DN}x9ebzNg$ z*+s|%rJg1*>3x86k+WBDALQ3RS3F*3E6$+EI7&@0Ma@IF-oHOTm>RQ|L87ILlQ-U3 zkGs2Nj@$H8PrLVg*PUO?FrOFvzz!SXAu*n^5eR_i%>xPi{PQJ#`|SZr3DkwgvTdJ) zBcur3*sx;+L`*;X{(ZfdkkUnV)9`1EF__Pry%M$QbU$T^M-QGOO5P~OI_!vJ#UV*jv^Up^pJw4TYSd$n= z`XYLm!vPnU$De|EaW{^`!$Z4QhL5%$y(P}rCN_4mb(1j52Pr!y)Akt&;(C$sA<%DEQ`ViJxJUjsNd4&)xj5#Le zDbaTQ4(5@DZHi+!0248GgOlI`&dzGw-p*b}swG-I7i-S(`ST+;C@6)y`z0{BXKuf~eSg6D`Fz8FoC2X-IEmrRvcv-Sck6@Szi#&^ zgbD!)0ln$rygzZq!Eye;qyeOj-`V_l-+%aUj;hkHw)xveaC38phldrk)@ZvP4~r$P zF3xf*cyec4kyKc(`-(ddpNcPw#S-&bgV}7l4}hg#*$DRS2N7o$ zU%o!>?S2|vM+aO8BcD8zA<^+)`=zIFe3pn0`01z1jF!E{i$|rF=sJtOH>j%;y)jrU z*C@1#ZD?_Zfe`4r0iGr>8rQz#TDN=Qk3B;?1nahgbsiVz^C*{3Tfh*3sr0Nfm|~FR zCIo;lUzZ0l6+1CVDlPoB;s*fCX0umsO!1MNs;7LNvjKnk%N36=k5I3BBh`!$0^Yx$ zfm1>VSZi_ru)vQ$-o#e!;he*e zA&8g9oKYy>NKa3hN8d+4Ib!z@&snKpF}61g-ngjM7O%2;uv zJ>F+Cc}qZR4IN1%Ox+InumAdtx~fLbgM~1Mz?q2PmPFs1CvQH4z^rLDr#?#M@dk62 z6^K9~U^XjJRhlLAS_5Oa$(AN!@}#$@ltKV=ACu=9va|Hi{pdpC_@9j!I0x`u)PfdwRdAo$=0md~bB zRYgp#L==DEiec9|6a^1~mQr%tnN~2?psFj5k!W-3hs7HVbo)=;{3Pw7qhbheHdDcM zR1=xaDpXa0vXm$a?!8P?TrMvg^u5Pw+2LW)GKXOB`-NbDi>Br-4~A%KUL3+~R^r{e z&An%$AoP~8!h42&Qz|CJ>y0>dp77Jp*ZA*$eBBUH(yZaZhv&$+fYjVG@4biZEmT#Y zEDJQX9^K7SiKv=^0nAESc^QX(dNe* zc2n0}6OasuY0Xo>%R)1aEAtU4f>mzImB+cp*E3w-%yECW#^SMyyhOfA%ogZ13NTYI z0ukZeyEDvYI$PJ>9k);`DJQ{?)Ih@3D1owkx*^Eqiw3j-o}KG(b9Ij2|NK4~a}a<^ zmr-GyCxgvqC8tWU1U*C|)6eXc!$+Ea4&2<#@ZrN5?(WuDEIKrC@MM|*N<>fYKXg&+ zZ%F?xG^cg%ZqHGcD$C~xL8JKPn3v7ZNrcO*2G=)ptk)gBep^F{{XaPzx~;FTXJ~58 z0}X`0{e83|+H?u=y)zAV5D2~D+Iv~DS2z@~rlAj=38QJ4Db17;uyN-7&I5;lx^D2p z#|xB|WGQ(^lMDA855&5{si;-q&p#hgXq6jag7+}7^nHrK=koW?=CgFYE>u445YN9- z(`WbIqbf`MkH0l|c<9i!>&c*7YmMOJ^tZY$@>sWrhi)gx8ynixPLJ5zTZc_5NO-|o?vth zMz#)8VP$9p`vejN2PxmaEkUtXuA*A#&~nS7L{+L+pYX8{qX?d{kni8tJWxX_Q1H1g zvZ|^{KICZg)3p`vd?KEcMD(`Wr)fClRJu$Aynlbjhw$N{M;aS*7$*@h)}2&;-X0ox zXuu?5v&WY&3t&KpQjuwtUfho6(bNUre)~5OJ_W+xb<}}6X=+)Ki&A_!|n2S~l*80rFd|E_9BDNyEPUO!86BozEZe4=$&P;9EWl=&% z0m8p`;ZlnF?skTC>+tO>!FbDp6_Hsq`C!R#iz0goBErq}Y&4hPH15w~ubb*W!87Ng z(0k zWp3YpJjdrhA7P!zMsVoFscgiIN}iurd04kGA@?4paxHtm6!eZan8HSSE@w`TF^{3$ z2_aEw&V2G=jTsCPaCKGZp;k{e03zn`GMFBeCzh(wks zw1#sYRaJ1Cc^5`t)Nl``+Q)N8?QrD=7{sYDO>)~I;sw9_e1m`d_t)6QJ${dJ*!J!T zpFW*M#kH5uBtGS!g+K@cjfaE?7KI)St$eWoNGVX(1KzwqE+KcV#k%d`Y{(GhsgiNq zs@d~-1@C>-G8{kbm{E0NM{NvYc+}f*G&4;TA8y{`vO`rD=zBAwb`3j^1h{2g#(?oP zxcsM>s`oTCNa zFaUFo|9;pquC>IsZw#CjMZt{ULCTuaK5JYAlz1Y!{C7;~-O^D|Ia?uUrAL{|vkX8; zfjSOA6hh!}*`n{=MtAO+o4yVErlaD$i_^Vq=KU!N=t7R9SdMWfhKoP^-fcqwad#2X zMu~j8=CfX#(MisgxM5p-tlAM#{Olf0qjvxrDLHUU6Uw%OTq*D*LTc)v%>N(L3Z=*H z|H%drLhL4qgBY_6Y^(~ZSHcG<&M+FHY@a_baC>tJp+ufhn7Hv6oXY*sY#Q7c11-gc zu92Yi5Y2R9JEb4RCv9sm9OjtH)ikJF5?H#%m=MeAJi1P4F_NEIuidC$VEYpD@q4N` za6?FB!{28VJZNM5;R~&Hj8C7s@kJp}*OFDWjK$sEdNinDzqgQiQgw=$lY%x4?t5Jn zP_aEqfYrzntjbdBz}Ij0c>n%7k3UUKBZuz)?RaJ5VYsEbC_AJIvS3^{d7@&B_S*;wq!9wGK~Y_E|%SYZNB zyeKOH8M*0q-#7GYab)AYb1+d*a@(yX8FLZEsS^!q8y8SQplBL+VzH+$U%unr?RD<{ zeOUmT_ziAyu*KB(r<%n!{aP!gQuQRF!M^$M66FpwtCGz_+^x zTwR<;cJ9leASpSOozHa?$4H3VW+(=ai{(Iy8B<~>_e#SZ(y42jD(dzAJCr6ihb#n& z4XB$nU#(kQT+EnlO(VnIQ=W?)z~C&t+;uEuc!2MgPJHk_4>{Nqa%V)5r<0}srtI=5 zZbDsiTeDHaHeV!K@sjEYy&2 zYyvlKDy;wtn4eX#AD$aS2rN_~rHtYdn>+W{-|ixhjZl{**52b`@rbL7^9XLd+z66V z$@T^(1r_hzh!H%B3*s}YD3IlxN1+RN=l{*SAL}fu)mUelxVPfJe*J=rvl{2;b5>_- zTb>k}g`fqeIBjd=7&WmsMqpVN$8LV`%d}R|TILx#BBq6j>_}VW%He|Y=?gm+{kOl~ z;?F-HBXN?o2>ZUr;*pyD)y?6zvU}9-OjjAf~{{gOH!(x6*cZ2`{002ovPDHLkV1iUPn4 Init APPL (END)"); -} - -@Override -public void onKeyboard(final KeySpecial special, final KeyKeyboard type, final Character value, final KeyStatus state) { - this.env.onKeyboard(special, type, value, state); -} - -@Override -public void onPointer(final KeySpecial special, final KeyType type, final int pointerID, final Vector2f pos, final KeyStatus state) { - this.env.onPointer(special, type, pointerID, pos, state); -} -*/ + public void setCurrentTool(MapToolInterface currentTool) { + this.currentTool = currentTool; + } +} \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java b/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java index f06a840..018a280 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java @@ -3,16 +3,18 @@ package sample.atriasoft.ege.mapFactory; import org.atriasoft.ege.Entity; import org.atriasoft.ege.Environement; import org.atriasoft.ege.camera.Camera; +import org.atriasoft.ege.camera.ProjectionInterface; +import org.atriasoft.ege.camera.ProjectionPerspective; import org.atriasoft.ege.components.ComponentPosition; import org.atriasoft.ege.components.ComponentRenderColoredStaticMesh; import org.atriasoft.ege.components.ComponentStaticMesh; import org.atriasoft.ege.tools.MeshGenerator; import org.atriasoft.esignal.Connection; import org.atriasoft.etk.Uri; -import org.atriasoft.etk.math.Matrix4f; import org.atriasoft.etk.math.Transform3D; import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.event.EventEntry; import org.atriasoft.ewol.event.EventInput; import org.atriasoft.ewol.event.EventTime; import org.atriasoft.ewol.widget.Widget; @@ -35,6 +37,11 @@ public class EgeScene extends Widget { self.markToRedraw(); } + // Widget display camera + public Camera mainView; + // Widget view mode + public ProjectionInterface projection; + // Environment model system. protected Environement env; /// Periodic call handle to remove it when needed @@ -51,10 +58,12 @@ public class EgeScene extends Widget { this.env = new Environement(); // default camera.... - final Camera mainView = new Camera(); - this.env.addCamera("default", mainView); - mainView.setPitch((float) Math.PI * -0.25f); - mainView.setPosition(new Vector3f(4, -5, 5)); + this.mainView = new Camera(); + this.env.addCamera("default", this.mainView); + this.mainView.setPitch((float) Math.PI * -0.25f); + this.mainView.setPosition(new Vector3f(4, -5, 5)); + + this.projection = new ProjectionPerspective(); } @@ -77,22 +86,26 @@ public class EgeScene extends Widget { Log.error("min size = " + this.minSize); } - private float getAspectRatio() { + protected float getAspectRatio() { return this.size.x() / this.size.y(); } + @Override + public void onChangeSize() { + super.onChangeSize(); + // update the projection matrix on the view size; + this.projection.updateMatrix(getSize()); + } + @Override protected void onDraw() { - //Log.info("==> appl Draw ..."); - final Vector2f size = getSize(); // Store openGl context. OpenGL.push(); // set projection matrix: - final Matrix4f tmpProjection = Matrix4f.createMatrixPerspective(3.14f * 0.5f, getAspectRatio(), 0.1f, 50000); - OpenGL.setMatrix(tmpProjection); + OpenGL.setMatrix(this.projection.getMatrix()); // set the basic openGL view port: (Draw in all the windows...) - OpenGL.setViewPort(new Vector2f(0, 0), size); + OpenGL.setViewPort(new Vector2f(0, 0), getSize()); // clear background //final Color bgColor = new Color(0.0f, 1.0f, 0.0f, 1.0f); @@ -102,6 +115,7 @@ public class EgeScene extends Widget { OpenGL.clear(OpenGL.ClearFlag.clearFlag_depthBuffer); OpenGL.enable(Flag.flag_depthTest); this.env.render(20, "default"); + onDrawScene(); OpenGL.disable(Flag.flag_depthTest); OpenGL.clear(OpenGL.ClearFlag.clearFlag_depthBuffer); @@ -109,11 +123,24 @@ public class EgeScene extends Widget { OpenGL.pop(); } + protected void onDrawScene() { + // nothing to do... + } + + @Override + public boolean onEventEntry(final EventEntry event) { + this.env.onKeyboard(event.specialKey(), event.type(), event.getChar(), event.status()); + return true; + } + @Override public boolean onEventInput(final EventInput event) { + keepFocus(); Vector2f relPos = relativePosition(event.pos()); - Log.warning("Event on Input ... " + event + " relPos = " + relPos); - return false; + //Log.warning("Event on Input ... " + event + " relPos = " + relPos); + this.env.onPointer(event.specialKey(), event.type(), event.inputId(), relPos, event.status()); + + return true; } @Override diff --git a/samples/src/sample/atriasoft/ege/mapFactory/Ground.java b/samples/src/sample/atriasoft/ege/mapFactory/Ground.java index a6d0584..2b700b2 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/Ground.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/Ground.java @@ -1,9 +1,17 @@ package sample.atriasoft.ege.mapFactory; +import java.util.function.BiFunction; + +import org.atriasoft.etk.Color; +import org.atriasoft.etk.math.Transform3D; +import org.atriasoft.etk.math.Vector3f; import org.atriasoft.etk.math.Vector4f; +import org.atriasoft.gale.resource.ResourceColored3DObject; import org.atriasoft.loader3d.model.Material; import org.atriasoft.loader3d.resources.ResourceMeshHeightMap; +import toolbox.Maths; + public class Ground { int sizeX = 16; int sizeY = 16; @@ -30,11 +38,46 @@ public class Ground { } } + public void changeHeightOfElement(Vector3f position, float distance, BiFunction applyer) { + for (int yyy = 0; yyy < this.sizeY; yyy++) { + for (int xxx = 0; xxx < this.sizeX; xxx++) { + float offset = 0.0f; + if (xxx % 2 == 1) { + offset = 0.5f; + } + float dist2 = position.less(xxx, yyy + offset, 0).length2(); + if (dist2 < distance * distance) { + this.heightMap[yyy][xxx] = applyer.apply(this.heightMap[yyy][xxx], Maths.sqrt(dist2)); + } + } + } + updateMesh(); + } + public ResourceMeshHeightMap createMesh() { return this.mesh; } + public void drawDynamicElement(ResourceColored3DObject dynamicElement, Vector3f position, float distance) { + for (int yyy = 0; yyy < this.sizeY; yyy++) { + for (int xxx = 0; xxx < this.sizeX; xxx++) { + float dist2 = position.less(xxx, yyy, 0).length2(); + if (dist2 < distance * distance) { + float coneHeight = 0.6f; + float offset = 0.0f; + if (xxx % 2 == 1) { + offset = 0.5f; + } + Transform3D tmpTransform = new Transform3D(new Vector3f(xxx, yyy + offset, this.heightMap[yyy][xxx] + coneHeight * 0.5f)); + dynamicElement.drawCone(coneHeight * 0.5f, coneHeight, 10, 3, tmpTransform.getOpenGLMatrix(), Color.RED); + } + } + } + + } + public void updateMesh() { + this.mesh.clearData(); Material mat = new Material(); this.mesh.addMaterial(this.baseNamePalette, mat); mat.setAmbientFactor(new Vector4f(1, 0, 0, 1.0f)); diff --git a/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java b/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java index 4bba2ff..ba72a3a 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java @@ -6,6 +6,8 @@ import org.atriasoft.ewol.widget.Sizer; import org.atriasoft.ewol.widget.Sizer.DisplayMode; import org.atriasoft.ewol.widget.Windows; +import sample.atriasoft.ege.mapFactory.tools.ToolMapHeight; + public class MainWindows extends Windows { public static void eventButtonIncrease(final MainWindows self) { @@ -18,7 +20,20 @@ public class MainWindows extends Windows { } } + public static void eventButtonTool(final MainWindows self) { + //Vector2b state = self.testWidget.getPropertyFill(); + //self.testWidget.setPropertyFill(state.withY(!state.y())); + if (self.toolButton.getPropertyValue() == "Brush") { + self.toolButton.setPropertyValue("Heigher"); + self.scene.setCurrentTool(new ToolMapHeight()); + } else { + self.toolButton.setPropertyValue("Brush"); + self.scene.setCurrentTool(null); + } + } + Button heightButton; + Button toolButton; ApplScene scene; public MainWindows() { @@ -40,12 +55,23 @@ public class MainWindows extends Windows { sizerMenu.setPropertyFill(Vector2b.TRUE_TRUE); sizerHoryMain.subWidgetAdd(sizerMenu); + this.toolButton = new Button(); + this.toolButton.setPropertyValue("Heigher"); + this.toolButton.setPropertyExpand(Vector2b.TRUE_FALSE); + this.toolButton.setPropertyFill(Vector2b.TRUE_TRUE); + sizerMenu.subWidgetAdd(this.toolButton); + this.toolButton.signalClick.connectAuto(this, MainWindows::eventButtonTool); + this.heightButton = new Button(); this.heightButton.setPropertyValue("Increase"); this.heightButton.setPropertyExpand(Vector2b.TRUE_FALSE); this.heightButton.setPropertyFill(Vector2b.TRUE_TRUE); sizerMenu.subWidgetAdd(this.heightButton); this.heightButton.signalClick.connectAuto(this, MainWindows::eventButtonIncrease); + + // set default tools: + this.scene.setCurrentTool(new ToolMapHeight()); + } } \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java b/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java index 3fb7072..86e24dc 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java @@ -11,10 +11,10 @@ public class MapFactoryMain { Ewol.init(); Ege.init(); Uri.setGroup("DATA", "data/"); - Uri.setGroup("RES", "res"); - //Uri.addLibrary("loxelEngine", MainCollisionTest.class, "testDataLoxelEngine/"); + //Uri.setGroup("RES", "res"); + //Uri.addLibrary("loxelEngine", MapFactoryMain.class, "testDataLoxelEngine/"); //Uri.addLibrary("plop", Appl.class, "resources/mapFactory/"); - Uri.setApplication(Appl.class, "lowPoly");//, "resources/mapFactory/"); + Uri.setApplication(Appl.class, "mapFactory");//, "resources/mapFactory/"); Ewol.run(new Appl(), args); } diff --git a/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java b/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java new file mode 100644 index 0000000..91b17bc --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java @@ -0,0 +1,12 @@ +package sample.atriasoft.ege.mapFactory.model; + +import sample.atriasoft.ege.mapFactory.Ground; + +public class Map { + public Ground ground = new Ground(); + + public void updateMesh() { + this.ground.updateMesh(); + } + +} diff --git a/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java b/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java new file mode 100644 index 0000000..e350430 --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java @@ -0,0 +1,16 @@ +package sample.atriasoft.ege.mapFactory.tools; + +import org.atriasoft.ewol.event.EventEntry; +import org.atriasoft.ewol.event.EventInput; + +import sample.atriasoft.ege.mapFactory.EgeScene; +import sample.atriasoft.ege.mapFactory.model.Map; + +public interface MapToolInterface { + void onDraw(Map map); + + boolean onEventEntry(final EventEntry event, Map map, EgeScene widget); + + boolean onEventInput(final EventInput event, Map relPos, EgeScene widget); + +} \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java b/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java new file mode 100644 index 0000000..2d2fa06 --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java @@ -0,0 +1,120 @@ +package sample.atriasoft.ege.mapFactory.tools; + +import org.atriasoft.ege.geometry.Ray; +import org.atriasoft.etk.Color; +import org.atriasoft.etk.math.Transform3D; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.event.EventEntry; +import org.atriasoft.ewol.event.EventInput; +import org.atriasoft.gale.key.KeyStatus; +import org.atriasoft.gale.resource.ResourceColored3DObject; + +import sample.atriasoft.ege.mapFactory.EgeScene; +import sample.atriasoft.ege.mapFactory.Log; +import sample.atriasoft.ege.mapFactory.model.Map; +import toolbox.Maths; + +public class ToolMapHeight implements MapToolInterface { + Vector3f positionRay = null; + float widthBrush = 3.0f; + float maxBrush = 10.0f; + float minBrush = -10.0f; + ResourceColored3DObject dynamicElement; + + public ToolMapHeight() { + this.dynamicElement = ResourceColored3DObject.create(); + } + + @Override + public void onDraw(Map map) { + // TODO Auto-generated method stub + if (this.positionRay != null) { + map.ground.drawDynamicElement(this.dynamicElement, this.positionRay, this.widthBrush); + float size = this.maxBrush - this.minBrush; + Transform3D tmpTransform = new Transform3D(this.positionRay.add(new Vector3f(0.0f, 0.0f, this.minBrush + size * 0.5f))); + this.dynamicElement.drawCylinder(this.widthBrush, size, 10, 22, tmpTransform.getOpenGLMatrix(), Color.AZURE.withA(0.5f), false, true); + } + + } + + @Override + public boolean onEventEntry(EventEntry event, Map map, EgeScene widget) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onEventInput(EventInput event, Map map, EgeScene widget) { + Vector2f relPos = widget.relativePosition(event.pos()); + // simple ray-cast on the ground + Ray mouseRay = widget.mainView.getRayFromScreen(widget.projection, widget.getSize(), relPos); + this.positionRay = mouseRay.intersectPlane(new Vector3f(0.0f, 0.0f, 1.0f), 0.0f); + /* + if (this.positionRay != null) { + this.posRay.setTransform(this.posRay.getTransform().withPosition(this.positionRay)); + } + */ + if (event.inputId() == 1 && (event.status() == KeyStatus.move || event.status() == KeyStatus.down)) { + if (this.positionRay != null) { + map.ground.changeHeightOfElement(this.positionRay, this.widthBrush, (value, distance) -> { + if (value > this.maxBrush) { + return value; + } + if (value < this.minBrush) { + return Maths.avg(-128.0f, value + 0.1f, this.maxBrush); + } + return Maths.avg(this.minBrush, value + 0.1f, this.maxBrush); + }); + } + return true; + } + if (event.inputId() == 3 && (event.status() == KeyStatus.move || event.status() == KeyStatus.down)) { + if (this.positionRay != null) { + map.ground.changeHeightOfElement(this.positionRay, this.widthBrush, (value, distance) -> { + if (value < this.minBrush) { + return value; + } + if (value > this.maxBrush) { + return Maths.avg(this.minBrush, value - 0.1f, 128.0f); + } + return Maths.avg(this.minBrush, value - 0.1f, this.maxBrush); + }); + } + return true; + } + // max brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft() && event.specialKey().getCtrlLeft())) { + this.maxBrush = Maths.avg(this.minBrush + 0.1f, this.maxBrush + 0.1f, 128.0f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft() && event.specialKey().getCtrlLeft())) { + this.maxBrush = Maths.avg(this.minBrush + 0.1f, this.maxBrush - 0.1f, 128.0f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + // min brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft())) { + this.minBrush = Maths.avg(-128.0f, this.minBrush + 0.1f, this.maxBrush - 0.1f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft())) { + this.minBrush = Maths.avg(-128.0f, this.minBrush - 0.1f, this.maxBrush - 0.1f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + // width brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getCtrlLeft())) { + this.widthBrush = Maths.avg(0.1f, this.widthBrush + 0.1f, 30.0f); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getCtrlLeft())) { + this.widthBrush = Maths.avg(0.1f, this.widthBrush - 0.1f, 30.0f); + return true; + } + return false; + } + +} diff --git a/src/org/atriasoft/ege/ControlCameraSimple.java b/src/org/atriasoft/ege/ControlCameraSimple.java index 5b6aee0..d69f57e 100644 --- a/src/org/atriasoft/ege/ControlCameraSimple.java +++ b/src/org/atriasoft/ege/ControlCameraSimple.java @@ -12,9 +12,6 @@ import org.atriasoft.gale.key.KeyStatus; public class ControlCameraSimple implements ControlInterface { private final Camera camera; - private float distanceFromCenter = 20; - private float angleZ = 0; - private float pitch = 0; private Vector2f lastMousePosition = null; private boolean moveUp = false; private boolean moveLeft = false; @@ -44,10 +41,10 @@ public class ControlCameraSimple implements ControlInterface { if (event.type() == KeyKeyboard.LEFT) { this.moveLeft = getState(event.status(), this.moveLeft); } - if (!event.specialKey().getCtrl() && event.type() == KeyKeyboard.RIGHT) { + if (event.type() == KeyKeyboard.RIGHT) { this.moveRight = getState(event.status(), this.moveRight); } - if (!event.specialKey().getCtrl() && event.type() == KeyKeyboard.DOWN) { + if (event.type() == KeyKeyboard.DOWN) { this.moveDown = getState(event.status(), this.moveDown); } this.ctrlIsSet = event.specialKey().getCtrl(); @@ -56,17 +53,20 @@ public class ControlCameraSimple implements ControlInterface { @Override public boolean onEventInput(final EventInput event, final Vector2f relativePosition) { - Log.info("" + event); // TODO Auto-generated method stub if (event.inputId() == 4) { + Vector3f delta = this.camera.getConvertionMatrix().transpose().multiply(new Vector3f(0,0,-1)); if (event.status() == KeyStatus.down) { - this.distanceFromCenter -= 1; + this.camera.setPosition(this.camera.getPosition().add(delta.multiply(1.0f))); } - } else if (event.inputId() == 5) { + } + if (event.inputId() == 5) { + Vector3f delta = this.camera.getConvertionMatrix().transpose().multiply(new Vector3f(0,0,-1)); if (event.status() == KeyStatus.down) { - this.distanceFromCenter += 1; + this.camera.setPosition(this.camera.getPosition().add(delta.multiply(-1.0f))); } - } else if (event.inputId() == 2) { + } + if (event.inputId() == 2) { if (event.status() == KeyStatus.down) { this.lastMousePosition = event.pos(); } else if (event.status() == KeyStatus.move) { @@ -83,7 +83,6 @@ public class ControlCameraSimple implements ControlInterface { this.camera.setPitch((float) -Math.PI); } this.camera.setRoll(this.camera.getRoll() + (float) Math.toRadians(delta.x())); - Log.info("Change camera: " + this.camera.getYaw() + " " + this.camera.getPitch()); if (this.camera.getRoll() > Math.PI) { this.camera.setRoll(this.camera.getRoll() - (float) Math.PI * 2.0f); } @@ -97,24 +96,26 @@ public class ControlCameraSimple implements ControlInterface { @Override public void periodicCall(final EventTime event) { + float roll = this.camera.getRoll(); if (this.moveLeft != this.moveRight) { + Vector3f orientation = new Vector3f(-(float)Math.cos(roll), (float)Math.sin(roll), 0); if (this.moveRight) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0.1f, 0, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(-0.1f))); } else { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(-0.1f, 0, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(0.1f))); } } if (!this.ctrlIsSet) { if (this.moveUp != this.moveDown) { + Vector3f orientation = new Vector3f((float)Math.sin(roll), (float)Math.cos(roll), 0); if (this.moveUp) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0.1f, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(0.1f))); } else { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, -0.1f, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(-0.1f))); } } } else if (this.moveUp != this.moveDown) { if (this.moveUp) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0, 0.1f))); } else { this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0, -0.1f))); diff --git a/src/org/atriasoft/ege/Environement.java b/src/org/atriasoft/ege/Environement.java index 3db8db7..6ab6927 100644 --- a/src/org/atriasoft/ege/Environement.java +++ b/src/org/atriasoft/ege/Environement.java @@ -71,7 +71,6 @@ public class Environement { addEngine(new EngineAI(this)); addEngine(new EngineDynamicMeshs(this)); addEngine(new EngineRender(this)); - //addEngine(new EnginePhysics(this)); addEngine(new EnginePhysics(this)); addEngine(new EngineParticle(this)); addEngine(new EngineLight(this)); diff --git a/src/org/atriasoft/ege/camera/Camera.java b/src/org/atriasoft/ege/camera/Camera.java index 502a348..67a6dbc 100644 --- a/src/org/atriasoft/ege/camera/Camera.java +++ b/src/org/atriasoft/ege/camera/Camera.java @@ -1,14 +1,15 @@ package org.atriasoft.ege.camera; +import org.atriasoft.ege.camera.ProjectionInterface.ValueLine; +import org.atriasoft.ege.geometry.Ray; import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector3f; - -//import entities.Player; -//import renderEngine.DisplayManager; +import org.atriasoft.etk.math.Vector4f; public class Camera { private float pitch = 0; - private Vector3f position = new Vector3f(0, 0, 2); + private Vector3f position = new Vector3f(0, 0, 0); private float roll = 0; private float yaw = 0; @@ -22,12 +23,6 @@ public class Camera { matrix = matrix.rotate(new Vector3f(0, 1, 0), getYaw()); matrix = matrix.rotate(new Vector3f(0, 0, 1), getRoll()); matrix = matrix.translate(new Vector3f(-this.position.x(), -this.position.y(), -this.position.z())); - /* - matrix = matrix.rotate(new Vector3f(1, 0, 0), 0.0f); - matrix = matrix.rotate(new Vector3f(0, 1, 0), 0.0f); - matrix = matrix.rotate(new Vector3f(0, 0, 1), 0.75f); - matrix = matrix.translate(new Vector3f(0, 0, -7)); - */ return matrix; } @@ -62,5 +57,18 @@ public class Camera { public void setYaw(final float yaw) { this.yaw = yaw; } - + + public ValueLine reverseTransform(ValueLine basicValues) { + Matrix4f cameraMatrix = getConvertionMatrix().transpose(); + // invert Matrix: + Matrix4f cameraMatrixInverted = cameraMatrix.invert(); + + return new ValueLine(cameraMatrixInverted.multiply(basicValues.near()), // compute near + cameraMatrixInverted.multiply(basicValues.far())); // compute far + } + public Ray getRayFromScreen(ProjectionInterface projection, Vector2f diplaySize, Vector2f mousePosition) { + ValueLine elem = projection.reverseTransform(diplaySize, mousePosition); + ValueLine result = reverseTransform(elem); + return Ray.createFromPoint(result.near(), result.far()); + } } diff --git a/src/org/atriasoft/ege/camera/ProjectionInterface.java b/src/org/atriasoft/ege/camera/ProjectionInterface.java new file mode 100644 index 0000000..3f24100 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionInterface.java @@ -0,0 +1,14 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; + + +public interface ProjectionInterface { + public record ValueLine(Vector3f near, Vector3f far) {}; + Matrix4f getMatrix(); + Matrix4f updateMatrix(Vector2f diplaySize); + ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition); + +} diff --git a/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java b/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java new file mode 100644 index 0000000..3d82545 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java @@ -0,0 +1,69 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.etk.math.Vector4f; + +public class ProjectionOrthogonal implements ProjectionInterface { + + Matrix4f lastMatrix = Matrix4f.IDENTITY; + float angleViewRad = 3.14f * 0.5f; + float nearView = 0.1f; + float farView = 5000.0f; + + protected float getAspectRatio(Vector2f size) { + return size.x() / size.y(); + } + public void setAngleViewRad(float angle) { + this.angleViewRad = angle; + } + public float getAngleViewRad() { + return this.angleViewRad; + } + @Override + public Matrix4f getMatrix() { + return lastMatrix; + } + @Override + public Matrix4f updateMatrix(Vector2f diplaySize) { + lastMatrix = Matrix4f.createMatrixOrtho( + diplaySize.x() * -0.5f, diplaySize.x() * 0.5f, // width + diplaySize.y() * -0.5f, diplaySize.y() * 0.5f, // height + nearView, farView);; + return lastMatrix; + } + public float getNear() { + return nearView; + } + public void setNear(float nearView) { + this.nearView = nearView; + } + public float getFar() { + return farView; + } + public void setFar(float farView) { + this.farView = farView; + } + @Override + public ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition) { + float mouse_pos_x_clip = mousePosition.x() / diplaySize.x() * 2.0f - 1.0f; + float mouse_pos_y_clip = mousePosition.y() / diplaySize.y() * 2.0f - 1.0f; + Vector4f mouse_pos_near_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, -1.0f, 1.0f); + Vector4f mouse_pos_far_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, 1.0f, 1.0f); + + Matrix4f projectionMatrix = getMatrix().transpose(); + // invert Matrix: + Matrix4f projectionMatrixInverted = projectionMatrix.invert(); + + Vector4f mouse_pos_near_view = projectionMatrixInverted.multiply(mouse_pos_near_clip); + Vector4f mouse_pos_far_view = projectionMatrixInverted.multiply(mouse_pos_far_clip); + // only for perspective + //mouse_pos_near_view = mouse_pos_near_view.divide(mouse_pos_near_view.w()); + //mouse_pos_far_view = mouse_pos_far_view.divide(mouse_pos_far_view.w()); + + return new ValueLine(new Vector3f(mouse_pos_near_view.x(), mouse_pos_near_view.y(), mouse_pos_near_view.z()), + new Vector3f(mouse_pos_far_view.x(), mouse_pos_far_view.y(), mouse_pos_far_view.z())); + } + +} diff --git a/src/org/atriasoft/ege/camera/ProjectionPerspective.java b/src/org/atriasoft/ege/camera/ProjectionPerspective.java new file mode 100644 index 0000000..142e0a8 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionPerspective.java @@ -0,0 +1,55 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.etk.math.Vector4f; + +public class ProjectionPerspective implements ProjectionInterface { + Matrix4f lastMatrix = Matrix4f.IDENTITY; + float angleViewRad = 3.14f * 0.5f; + float nearView = 0.1f; + float farView = 5000.0f; + + protected float getAspectRatio(Vector2f size) { + return size.x() / size.y(); + } + public void setAngleViewRad(float angle) { + this.angleViewRad = angle; + } + public float getAngleViewRad() { + return this.angleViewRad; + } + @Override + public Matrix4f getMatrix() { + return lastMatrix; + } + @Override + public Matrix4f updateMatrix(Vector2f diplaySize) { + lastMatrix = Matrix4f.createMatrixPerspective(getAngleViewRad(), getAspectRatio(diplaySize), nearView, farView);; + return lastMatrix; + } + @Override + public ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition) { + + float mouse_pos_x_clip = mousePosition.x() / diplaySize.x() * 2.0f - 1.0f; + float mouse_pos_y_clip = mousePosition.y() / diplaySize.y() * 2.0f - 1.0f; + Vector4f mouse_pos_near_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, -1.0f, 1.0f); + Vector4f mouse_pos_far_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, 1.0f, 1.0f); + + Matrix4f projectionMatrix = getMatrix().transpose(); + // invert Matrix: + Matrix4f projectionMatrixInverted = projectionMatrix.invert(); + + Vector4f mouse_pos_near_view = projectionMatrixInverted.multiply(mouse_pos_near_clip); + Vector4f mouse_pos_far_view = projectionMatrixInverted.multiply(mouse_pos_far_clip); + // only for perspective + mouse_pos_near_view = mouse_pos_near_view.divide(mouse_pos_near_view.w()); + mouse_pos_far_view = mouse_pos_far_view.divide(mouse_pos_far_view.w()); + + return new ValueLine(new Vector3f(mouse_pos_near_view.x(), mouse_pos_near_view.y(), mouse_pos_near_view.z()), + new Vector3f(mouse_pos_far_view.x(), mouse_pos_far_view.y(), mouse_pos_far_view.z())); + + } + +} diff --git a/src/org/atriasoft/ege/engines/EnginePhysics.java b/src/org/atriasoft/ege/engines/EnginePhysics.java index 1f29b7a..1ebcfac 100644 --- a/src/org/atriasoft/ege/engines/EnginePhysics.java +++ b/src/org/atriasoft/ege/engines/EnginePhysics.java @@ -97,7 +97,6 @@ public class EnginePhysics extends Engine { @Override public void renderDebug(long deltaMili, Camera camera) { - // TODO Auto-generated method stub DebugDisplay.onDraw(); DebugDisplay.clear(); } @@ -113,7 +112,7 @@ public class EnginePhysics extends Engine { applyForces(TIME_STEP); // update AABB after because in rotation force, the Bounding box change... updateAABB(TIME_STEP); - // update the colision tree between each object in the room + // update the collision tree between each object in the room updateCollisionsAABB(TIME_STEP); updateCollisionsNarrowPhase(TIME_STEP); generateResultCollisionsForces(TIME_STEP); diff --git a/src/org/atriasoft/ege/geometry/Ray.java b/src/org/atriasoft/ege/geometry/Ray.java index 7f02b18..9e82cf7 100644 --- a/src/org/atriasoft/ege/geometry/Ray.java +++ b/src/org/atriasoft/ege/geometry/Ray.java @@ -2,33 +2,176 @@ package org.atriasoft.ege.geometry; import org.atriasoft.etk.math.Vector3f; -public class Ray { +import toolbox.Maths; + +public record Ray(Vector3f origin, Vector3f direction) { public static Ray createFromPoint(final Vector3f origin, final Vector3f destination) { - Ray out = new Ray(origin, destination.less(origin)); - out.normalizeDirection(); - return out; + return new Ray(origin, destination.less(origin).safeNormalize()); } - public Vector3f origin; - - public Vector3f direction; - public Ray() { - this.origin = Vector3f.ZERO; - this.direction = new Vector3f(0.0f, 0.0f, 1.0f); + this(Vector3f.ZERO, new Vector3f(0.0f, 0.0f, 1.0f)); } public Ray(final Vector3f origin, final Vector3f direction) { this.origin = origin; this.direction = direction; } - - public void normalizeDirection() { - this.direction = this.direction.safeNormalize(); - } - + @Override public String toString() { return "Ray [origin=" + this.origin + ", direction=" + this.direction + "]"; } + + /** + * Get the position on the top or bottom plane describe in parameters. + * @param normalPlane Normal description of the plane. + * @param distancePlane distance to define the plane position. + * @return position on the plane intersection (null if not collide). + */ + public Vector3f intersectPlane(Vector3f normalPlane, float distancePlane) { + float denom = normalPlane.dot(this.direction); + // Prevent divide by zero: + if (Math.abs(denom) <= 1e-4f) { + return null; + } + float t = -(normalPlane.dot(this.origin) + distancePlane) / normalPlane.dot(this.direction); + + // Use pointy end of the ray. + // It is technically correct to compare t < 0, + // but that may be undesirable in a raytracer. + if (t <= 1e-4) { + return null; + } + return this.origin.add(this.direction.multiply(t)); + } + /** + * Get the position on the top plane describe in parameters. + * @param normalPlane Normal description of the plane. + * @param distancePlane distance to define the plane position. + * @return position on the plane intersection (null if not collide). + */ + public Vector3f intersectPlaneTop(Vector3f normalPlane, float distancePlane) { + float denom = normalPlane.dot(this.direction); + + if (-denom <= 1e-4f) { + return null; + } + + float t = -(normalPlane.dot(this.origin) + distancePlane) / normalPlane.dot(this.direction); + + // Use pointy end of the ray. + // It is technically correct to compare t < 0, + // but that may be undesirable in a raytracer. + if (t <= 1e-4) { + return null; + } + return this.origin.add(this.direction.multiply(t)); + } + + public boolean intersectSphere(Vector3f sphereCenter, float sphereSize) { + //solve for tc + Vector3f L = sphereCenter.less(this.origin); + float tc = L.dot(this.direction); + if ( tc < 0.0f ) { + return false; + } + float d2 = tc*tc - L.length2(); + float radius2 = sphereSize * sphereSize; + if ( d2 > radius2) { + return false; + } + return true; + } + public record ReturnIntersectSphere(Vector3f pos1, Vector3f pos2) {}; + + public ReturnIntersectSphere intersectSpherePos(Vector3f sphereCenter, float sphereSize) { + //solve for tc + Vector3f L = sphereCenter.less(this.origin); + float tc = L.dot(this.direction); + if ( tc < 0.0f ) { + return null; + } + float d2 = tc*tc - L.length2(); + + float radius2 = sphereSize * sphereSize; + if ( d2 > radius2) { + return null; + } + + //solve for t1c + float t1c = (float) Math.sqrt( radius2 - d2 ); + + //solve for intersection points + float t1 = tc - t1c; + float t2 = tc + t1c; + + return new ReturnIntersectSphere(this.origin.add(this.direction().multiply(t1)), + this.origin.add(this.direction().multiply(t2)) ); + } + + Vector3f intersectTriangle( + Vector3f orig, Vector3f dir, + Vector3f v0, Vector3f v1, Vector3f v2) { + float t = 0; // output distance. + // compute plane's normal + Vector3f v0v1 = v1.less(v0); + Vector3f v0v2 = v2.less(v0); + // no need to normalize + Vector3f N = v0v1.cross(v0v2); // N + float area2 = N.length(); + + // Step 1: finding P + + // check if ray and plane are parallel ? + float NdotRayDirection = N.dot(dir); + if (Math.abs(NdotRayDirection) < 0.0000001) // almost 0 + return null; // they are parallel so they don't intersect ! + + // compute d parameter using equation 2 + float d = -N.dot(v0); + + // compute t (equation 3) + t = -(N.dot(orig) + d) / NdotRayDirection; + + // check if the triangle is in behind the ray + if (t < 0) { + return null; // the triangle is behind + } + + // compute the intersection point using equation 1 + Vector3f P = orig.add(dir.multiply(t)); + + // Step 2: inside-outside test + Vector3f C; // vector perpendicular to triangle's plane + + // edge 0 + Vector3f edge0 = v1.less(v0); + Vector3f vp0 = P.less(v0); + C = edge0.cross(vp0); + if (N.dot(C) < 0) { + return null; // P is on the right side + } + + // edge 1 + Vector3f edge1 = v2.less(v1); + Vector3f vp1 = P.less(v1); + C = edge1.cross(vp1); + if (N.dot(C) < 0) { + return null; // P is on the right side + } + + // edge 2 + Vector3f edge2 = v0.less(v2); + Vector3f vp2 = P.less(v2); + C = edge2.cross(vp2); + if (N.dot(C) < 0) { + return null; // P is on the right side; + } + + return this.origin.add(this.direction().multiply(t)); // this ray hits the triangle + } + + + } diff --git a/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java b/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java index 49dba4f..d59f1ae 100644 --- a/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java +++ b/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java @@ -7,20 +7,10 @@ import org.atriasoft.phyligram.ColisionPoint; import org.atriasoft.phyligram.PhysicSphere; import org.atriasoft.phyligram.PhysicTriangle; +import toolbox.Maths; + // https://realtimecollisiondetection.net/blog/?p=103 public class ToolCollisionSphereWithTriangle { - public static float clamp(float val, float min, float max) { - return Math.max(min, Math.min(max, val)); - } - - public static Vector3f getClosestPointOnFiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { - Vector3f lineDirection = lineEnd.less(lineStart); - float lineLength = lineDirection.length(); - lineDirection = lineDirection.normalize(); - float position = point.less(lineStart).dot(lineDirection); - float ProjectionLength = clamp(position, 0, lineLength); - return lineStart.add(lineDirection.multiply(ProjectionLength)); - } public static ColisionPoint getCollisionPoint(PhysicSphere sphere1, PhysicTriangle shapeReference) { Plane plane = new Plane(shapeReference.getTriangleGlobalPos()); @@ -66,13 +56,13 @@ public class ToolCollisionSphereWithTriangle { System.out.println("Not in center"); // now we need to check if we have a collision with the border. - Vector3f nearestPointP1 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); + Vector3f nearestPointP1 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); float distanceP1Square = Vector3f.length2(nearestPointP1, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP1Square=" + distanceP1Square); - Vector3f nearestPointP2 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); + Vector3f nearestPointP2 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); float distanceP2Square = Vector3f.length2(nearestPointP2, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP2Square=" + distanceP2Square); - Vector3f nearestPointP3 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); + Vector3f nearestPointP3 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); float distanceP3Square = Vector3f.length2(nearestPointP3, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP3Square=" + distanceP3Square); float distanceFinal; @@ -133,19 +123,19 @@ public class ToolCollisionSphereWithTriangle { System.out.println("Not in center"); // now we need to check if we have a collision with the border. - Vector3f nearestPointP1 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); + Vector3f nearestPointP1 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); float distanceP1Square = Vector3f.length2(nearestPointP1, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP1Square=" + distanceP1Square); if (distanceP1Square < distance2) { return true; } - Vector3f nearestPointP2 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); + Vector3f nearestPointP2 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); float distanceP2Square = Vector3f.length2(nearestPointP2, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP2Square=" + distanceP2Square); if (distanceP2Square < distance2) { return true; } - Vector3f nearestPointP3 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); + Vector3f nearestPointP3 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); float distanceP3Square = Vector3f.length2(nearestPointP3, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP3Square=" + distanceP3Square); if (distanceP3Square < distance2) { diff --git a/src/toolbox/Maths.java b/src/toolbox/Maths.java index 574bf7e..8fbd7d4 100644 --- a/src/toolbox/Maths.java +++ b/src/toolbox/Maths.java @@ -49,5 +49,33 @@ public class Maths { matrix = matrix.rotate(new Vector3f(0, 1, 0), camera.getYaw()); return matrix; } + + public static float clamp(float val, float min, float max) { + return Math.max(min, Math.min(max, val)); + } + public static float avg(float min, float val, float max) { + return Math.max(min, Math.min(max, val)); + } + + public static Vector3f getClosestPointOnFiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { + Vector3f lineDirection = lineEnd.less(lineStart); + float lineLength = lineDirection.length(); + lineDirection = lineDirection.normalize(); + float position = point.less(lineStart).dot(lineDirection); + float ProjectionLength = clamp(position, 0, lineLength); + return lineStart.add(lineDirection.multiply(ProjectionLength)); + } + + public static Vector3f getClosestPointOnInfiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { + Vector3f lineDirection = lineEnd.less(lineStart); + lineDirection = lineDirection.normalize(); + float position = point.less(lineStart).dot(lineDirection); + return lineStart.add(lineDirection.multiply(position)); + } + + public static float sqrt(float dist2) { + // TODO Auto-generated method stub + return (float)Math.sqrt(dist2); + } }