From 96eb85d55ab7479a34c03ccc526eaa0bf421ab13 Mon Sep 17 00:00:00 2001 From: josua Date: Thu, 23 Jul 2020 11:00:39 +1000 Subject: [PATCH] Working on save cards and better culling options --- src/projectzombie/display/DisplayRender.java | 2 +- .../display/DisplayRenderUI.java | 9 +- src/projectzombie/display/DisplayWindow.java | 4 +- src/projectzombie/init/Models.java | 8 +- src/projectzombie/menu/MenuSaves.java | 32 ++++-- ...uiButtonModel.java => GUIButtonModel.java} | 15 +-- src/projectzombie/menu/gui/GUISavesCard.java | 92 ++++++++++++++++++ src/resources/shader/environmentRenderer.fsh | 7 +- src/resources/shader/environmentRenderer.vsh | 5 +- src/resources/texture/gui/label.png | Bin 4017 -> 8215 bytes 10 files changed, 147 insertions(+), 27 deletions(-) rename src/projectzombie/menu/gui/{GuiButtonModel.java => GUIButtonModel.java} (76%) create mode 100644 src/projectzombie/menu/gui/GUISavesCard.java diff --git a/src/projectzombie/display/DisplayRender.java b/src/projectzombie/display/DisplayRender.java index d42d701..0f214ea 100755 --- a/src/projectzombie/display/DisplayRender.java +++ b/src/projectzombie/display/DisplayRender.java @@ -116,7 +116,7 @@ public class DisplayRender GL33.glEnable(GL33.GL_DEPTH_TEST); GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1); - GL33.glUniform2f(Main.window.glsl_tex_cut, 0, 0); + GL33.glUniform4f(Main.window.glsl_discard_coords, -1, -1, 1, 1); ColorRange range = Main.world.getLayer().layergen.getLightLevel(); diff --git a/src/projectzombie/display/DisplayRenderUI.java b/src/projectzombie/display/DisplayRenderUI.java index f2e8efa..d3435de 100755 --- a/src/projectzombie/display/DisplayRenderUI.java +++ b/src/projectzombie/display/DisplayRenderUI.java @@ -79,15 +79,16 @@ public class DisplayRenderUI ModelGui model_temperature = Models.UI_TEMPERATURE; ModelGui model_water = Models.UI_WATER; - Matrix4 matrix = Matrix4.translate(-(79 * 15.0) / 160, -9.5 + (1.5 * 17) / 16, 0); + double offset = -(79 * 15.0) / 160; + Matrix4 matrix = Matrix4.translate(offset, -9.5 + (1.5 * 17) / 16, 0); model_health_b.setModel(matrix); model_health_b.render(); - GL33.glUniform2f(Main.window.glsl_tex_cut, 1, (float)MathHelpers.map( + GL33.glUniform4f(Main.window.glsl_discard_coords, -1, -1, (float)MathHelpers.map( Main.player.getHealth(), 0, Main.player.maxHealth(), - 0, model_health_f.getWidth())); + offset, model_health_f.getWidth() + offset), 1); model_health_f.setModel(matrix); model_health_f.render(); @@ -95,7 +96,7 @@ public class DisplayRenderUI double temperature = MathHelpers.smoothStep(Main.player.getTemperature()); double hydration = MathHelpers.smoothStep(1 - Main.player.getHydration()) * 0.75; - GL33.glUniform2f(Main.window.glsl_tex_cut, 0, 0); + GL33.glUniform4f(Main.window.glsl_discard_coords, -1, -1, 1, 1); GL33.glUniform4f(Main.window.glsl_color, (float)temperature, calculateGreen(temperature), 1 - (float)temperature, 1); diff --git a/src/projectzombie/display/DisplayWindow.java b/src/projectzombie/display/DisplayWindow.java index 14bd834..ef46a13 100755 --- a/src/projectzombie/display/DisplayWindow.java +++ b/src/projectzombie/display/DisplayWindow.java @@ -47,7 +47,7 @@ public class DisplayWindow implements IMainloopTask public int glsl_mist; public int glsl_color; public int glsl_contrast; - public int glsl_tex_cut; + public int glsl_discard_coords; public int glsl_model; public int glsl_camera; public int glsl_projection; @@ -136,7 +136,7 @@ public class DisplayWindow implements IMainloopTask glsl_projection = GL33.glGetUniformLocation(environmentRenderer.program, "projection"); glsl_projection_sun = GL33.glGetUniformLocation(environmentRenderer.program, "projection_sun"); glsl_time = GL33.glGetUniformLocation(environmentRenderer.program, "time"); - glsl_tex_cut = GL33.glGetUniformLocation(environmentRenderer.program, "tex_cut"); + glsl_discard_coords = GL33.glGetUniformLocation(environmentRenderer.program, "discard_coords"); glsl_color = GL33.glGetUniformLocation(environmentRenderer.program, "color"); glsl_contrast = GL33.glGetUniformLocation(environmentRenderer.program, "contrast"); glsl_billboard = GL33.glGetUniformLocation(environmentRenderer.program, "billboard"); diff --git a/src/projectzombie/init/Models.java b/src/projectzombie/init/Models.java index 474bd6f..cee3c0a 100755 --- a/src/projectzombie/init/Models.java +++ b/src/projectzombie/init/Models.java @@ -96,10 +96,10 @@ public class Models public static final ModelGui UI_BUTTON = new ModelGui(Resources.ATLAS.get("/gui/button_normal.png"), new Vec2d(12, 1.5)); public static final ModelGui UI_BUTTON_HOVER = new ModelGui(Resources.ATLAS.get("/gui/button_hover.png"), new Vec2d(12, 1.5)); - public static final ModelGui UI_BUTTON_DELETE = new ModelGui(Resources.ATLAS.get("/gui/button_delete.png"), new Vec2d(1.2, 1.2)); - public static final ModelGui UI_BUTTON_DELETE_HOVER = new ModelGui(Resources.ATLAS.get("/gui/button_delete_hover.png"), new Vec2d(1.2, 1.2)); - public static final ModelGui UI_BUTTON_PLAY = new ModelGui(Resources.ATLAS.get("/gui/button_play.png"), new Vec2d(1.2, 1.2)); - public static final ModelGui UI_BUTTON_PLAY_HOVER = new ModelGui(Resources.ATLAS.get("/gui/button_play_hover.png"), new Vec2d(1.2, 1.2)); + public static final ModelGui UI_BUTTON_DELETE = new ModelGui(Resources.ATLAS.get("/gui/button_delete.png"), new Vec2d(1.875, 1.875)); + public static final ModelGui UI_BUTTON_DELETE_HOVER = new ModelGui(Resources.ATLAS.get("/gui/button_delete_hover.png"), new Vec2d(1.875, 1.875)); + public static final ModelGui UI_BUTTON_PLAY = new ModelGui(Resources.ATLAS.get("/gui/button_play.png"), new Vec2d(1.875, 1.875)); + public static final ModelGui UI_BUTTON_PLAY_HOVER = new ModelGui(Resources.ATLAS.get("/gui/button_play_hover.png"), new Vec2d(1.875, 1.875)); public static final ModelGui UI_LABEL = new ModelGui(Resources.ATLAS.get("/gui/label.png"), new Vec2d(24, 3)); public static final ModelGui UI_HEALTH_FG = new ModelGui(Resources.ATLAS.get("/gui/health_full.png"), new Vec2d(6, 0.375)); diff --git a/src/projectzombie/menu/MenuSaves.java b/src/projectzombie/menu/MenuSaves.java index 65bb8b9..2006ea4 100644 --- a/src/projectzombie/menu/MenuSaves.java +++ b/src/projectzombie/menu/MenuSaves.java @@ -2,6 +2,8 @@ package projectzombie.menu; import java.util.Random; +import org.lwjgl.opengl.GL33; + import gl_engine.vec.Vec2d; import projectzombie.Main; import projectzombie.init.Layers; @@ -11,7 +13,8 @@ import projectzombie.menu.gui.GUI; import projectzombie.menu.gui.GUIAlignment; import projectzombie.menu.gui.GUIButton; import projectzombie.menu.gui.GUILabel; -import projectzombie.menu.gui.GuiButtonModel; +import projectzombie.menu.gui.GUISavesCard; +import projectzombie.menu.gui.GUIButtonModel; import projectzombie.menu.gui.components.ButtonBasic; import projectzombie.menu.gui.components.ButtonCallback; import projectzombie.menu.gui.components.ButtonSetting; @@ -21,7 +24,7 @@ public class MenuSaves extends Menu private static final Random rand = new Random(); private Menu parent; - private GUI gui; + private GUI gui, gui_cards; public MenuSaves(Menu parent) { @@ -31,7 +34,20 @@ public class MenuSaves extends Menu doGameRender = parent.doGameRender; showIngameGUI = parent.showIngameGUI; - gui = new GUI(); + gui = new GUI() + { + @Override + public void render() + { + GL33.glUniform4f(Main.window.glsl_discard_coords, -0.5f, -0.5f, 0.5f, 0.5f); + super.render(); + GL33.glUniform4f(Main.window.glsl_discard_coords, -1, -1, 1, 1); + } + }; + + gui_cards = new GUI(); + + input = new InputGUI(gui); keepMouse = false; @@ -44,8 +60,8 @@ public class MenuSaves extends Menu Main.menu = new MenuGame(); }); - GuiButtonModel buttonPlay = new GuiButtonModel(Models.UI_BUTTON_DELETE, Models.UI_BUTTON_DELETE_HOVER); - gui.add(buttonPlay); + GUISavesCard savesCard = new GUISavesCard(new Vec2d(0, 0)); + gui_cards.add(savesCard); buttonBack.setAlign(GUIAlignment.RIGHT); buttonCreate.setAlign(GUIAlignment.LEFT); @@ -57,14 +73,16 @@ public class MenuSaves extends Menu labelSaves.setText("Saves"); labelSaves.setSize(new Vec2d(1, 1)); labelSaves.setPos(new Vec2d(0, 6.8)); - gui.add(labelSaves); + gui_cards.add(labelSaves); gui.add(buttonBack); gui.add(buttonCreate); + gui.add(gui_cards); } @Override - public void render() { + public void render() + { gui.render(); } diff --git a/src/projectzombie/menu/gui/GuiButtonModel.java b/src/projectzombie/menu/gui/GUIButtonModel.java similarity index 76% rename from src/projectzombie/menu/gui/GuiButtonModel.java rename to src/projectzombie/menu/gui/GUIButtonModel.java index fa8b904..5c414db 100644 --- a/src/projectzombie/menu/gui/GuiButtonModel.java +++ b/src/projectzombie/menu/gui/GUIButtonModel.java @@ -5,14 +5,20 @@ import gl_engine.vec.Vec2d; import projectzombie.model.Model; import projectzombie.model.ModelGui; -public class GuiButtonModel implements GUIComponent +public class GUIButtonModel implements GUIComponent { + public interface GUIButtonModelCallback { + public void click(GUIButtonModel button); + } + + private GUIButtonModelCallback callback; private ModelGui modelHover; private ModelGui model; private Vec2d pos = new Vec2d(0, 0); - public GuiButtonModel(ModelGui model, ModelGui modelHover) { + public GUIButtonModel(ModelGui model, ModelGui modelHover, GUIButtonModelCallback callback) { + this.callback = callback; this.modelHover = modelHover; this.model = model; } @@ -43,14 +49,11 @@ public class GuiButtonModel implements GUIComponent @Override public void onRightClick(Vec2d mousePos) { - // TODO Auto-generated method stub - } @Override public void onMouseClick(Vec2d mousePos) { - // TODO Auto-generated method stub - + this.callback.click(this); } @Override diff --git a/src/projectzombie/menu/gui/GUISavesCard.java b/src/projectzombie/menu/gui/GUISavesCard.java new file mode 100644 index 0000000..cb8c036 --- /dev/null +++ b/src/projectzombie/menu/gui/GUISavesCard.java @@ -0,0 +1,92 @@ +package projectzombie.menu.gui; + +import gl_engine.matrix.Matrix4; +import gl_engine.vec.Vec2d; +import projectzombie.init.Models; +import projectzombie.model.ModelGui; + +public class GUISavesCard implements GUIComponent +{ + private static final ModelGui LABEL = Models.UI_LABEL; + + private Vec2d pos = new Vec2d(0, 0); + private GUIButtonModel buttonDelete; + private GUIButtonModel buttonPlay; + + public GUISavesCard(Vec2d pos) + { + pos.x -= LABEL.getWidth() / 2; + + this.pos = pos; + + buttonDelete = new GUIButtonModel(Models.UI_BUTTON_DELETE, Models.UI_BUTTON_DELETE_HOVER, button -> { + onDeletePressed(); + }); + + buttonPlay = new GUIButtonModel(Models.UI_BUTTON_PLAY, Models.UI_BUTTON_PLAY_HOVER, button -> { + onPlayPressed(); + }); + + buttonPlay.setPos(new Vec2d(-LABEL.getWidth()*122/256.0, LABEL.getHeight()*6/32.0)); + buttonDelete.setPos(new Vec2d(LABEL.getWidth()*102/256.0, LABEL.getHeight()*6/32.0)); + } + + public void onPlayPressed() { + + } + + public void onDeletePressed() { + + } + + @Override + public void render(Vec2d mousePos) + { + LABEL.setModel(Matrix4.translate(pos.x, pos.y, 0)); + LABEL.render(); + + buttonDelete.render(mousePos); + buttonPlay.render(mousePos); + } + + @Override + public void update(Vec2d mousePos) { + buttonDelete.update(mousePos); + buttonPlay.update(mousePos); + } + + @Override + public boolean checkMouseHover(Vec2d pos) { + return (this.pos.x > pos.x && this.pos.x + LABEL.getWidth() < pos.x && + this.pos.y > pos.y && this.pos.y + LABEL.getHeight() < pos.y); + } + + @Override + public void onRightClick(Vec2d pos) { + if(buttonDelete.checkMouseHover(pos)) + buttonDelete.onRightClick(pos); + if(buttonPlay.checkMouseHover(pos)) + buttonPlay.onRightClick(pos); + } + + @Override + public void onMouseClick(Vec2d pos) { + if(buttonDelete.checkMouseHover(pos)) + buttonDelete.onMouseClick(pos); + if(buttonPlay.checkMouseHover(pos)) + buttonPlay.onMouseClick(pos); + } + + @Override + public void onActivate() { + buttonDelete.onActivate(); + buttonPlay.onActivate(); + } + + @Override + public void onBack() { + buttonDelete.onBack(); + buttonPlay.onBack(); + } + +} diff --git a/src/resources/shader/environmentRenderer.fsh b/src/resources/shader/environmentRenderer.fsh index c26e95c..8e940c6 100644 --- a/src/resources/shader/environmentRenderer.fsh +++ b/src/resources/shader/environmentRenderer.fsh @@ -4,6 +4,7 @@ in vec3 pPos; in vec3 pTexture; in vec3 pLightMapPos; in vec3 pSunDepth; +in vec2 pVertex; in float pCameraDepth; flat in int pFlags; @@ -22,7 +23,7 @@ uniform vec3 lighting_day_high; uniform vec2 lightmap_offset; uniform vec2 lightmap_size; -uniform vec2 tex_cut; +uniform vec4 discard_coords; uniform vec4 color; uniform float contrast; @@ -99,5 +100,7 @@ void main() FragColor.b = min(1, FragColor.b); } - discard(textureRGB.a == 0 || (pPos.x > tex_cut.y && tex_cut.x > 0.5)); + discard(textureRGB.a == 0 || ( + pVertex.x < discard_coords.x || pVertex.y < discard_coords.y || + pVertex.x > discard_coords.z || pVertex.y > discard_coords.w)); } \ No newline at end of file diff --git a/src/resources/shader/environmentRenderer.vsh b/src/resources/shader/environmentRenderer.vsh index c0a7c2c..3a30cf6 100644 --- a/src/resources/shader/environmentRenderer.vsh +++ b/src/resources/shader/environmentRenderer.vsh @@ -11,6 +11,7 @@ out float pCameraDepth; out vec3 pSunDepth; out vec3 pLightMapPos; out vec3 pTexture; +out vec2 pVertex; out vec3 pPos; flat out int pFlags; @@ -65,7 +66,9 @@ void main() vec4 pos = vec4(aPos, 1) * (mod(type >> 3, 2) == 1 ? billboard : (mod(type, 2) == 1 ? rotated : mat4(1))) * translate(aOffset) * model; - gl_Position = pos * projection; + vec4 vertex = pos * projection; + gl_Position = vertex; + pVertex = vertex.xy / vertex.w; if(mode == 0) { pCameraDepth = mod(type >> 4, 2) == 1 ? 0 : min(1, mist * (-(pos * camera).z * 0.5 + 0.5)); diff --git a/src/resources/texture/gui/label.png b/src/resources/texture/gui/label.png index 7db9d82acd1cdcdfb09263ba38db8c27138a8632..45a3a9774ef719b21756e975332808ba59ba5523 100644 GIT binary patch literal 8215 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

b zEq+u=e$}hXmxGP(-)%T{X2<^O{reK9-Ve2}{q^P5)z!AizjOcAKmGdu!$W4{|MJ1_ WBDeU}-kJ=W_xE)5b6Mw<&;$Ttgt~bE literal 4017 zcmeAS@N?(olHy`uVBq!ia0y~yU}RumU{K&-V_;zTyK>nR1_s8KOlRi+PiJR^f};Gi z%$!sP291fe6Ky>XJIEZ358kRI%HAzfcp_k~PDhtTmS|Ui;uWs7Rx@ILDVk(@1jWd( zUT|IYE@tKPZIf6o84th&1AXhVaC&0(I)YH{lG zZf)T`_xp%o*rd=$#g76f>v{Y+QF`>T`8n6=tn(xdjbBavv1Fl(pkmX0yS*w zzD(O6#JqM4lif|qHEm<4P_hLV5RoLEp zvwmCDG8kP6eZ^*B!Q$36W$&}k@7{g8_s{n7oA>Oju|?I*lkU!7U|`@Z@Q5sCVBi)8 zVMc~ob0ioT7}!fZeO=j~u#2$>Sn*DAiC|#hJ>co$7*cWT?c9@-q^}CK{SPkoRNcBu z_6A=OAky z=6^E&Cu_goE&puM=QYVC_jcCSs7x96-p4BpctqP4{@NEV(I(aA=s9V{YpdSJD{Rh- zvNZnMcin(Ts?G77<Qe_nGpZ~5Q4^_jCo z+7@1j7hp->^>UYApvcW%vzA>f+Z`G?E&X|DXzKAbVcMp?%AQ<@1D0R*y!|#T_qNxh zMH-We{SF)4_<5o+&azy_ee&G-8eMWziVyxT`pAFy!oRn3f`5Fy9)G{~_uK8i{(ir2 z%G2EVe9mT8|I14sJnuzTP8sn2&#QVEo3TeZr|Q9y%($@2M?(zz;`^U{qE zWzNbGoOH#c_uA{NoVT{EeO4JJ(Z;6pV0&)%CYL}JPp+l|b>`UiL1o7s&^GFMsjoz=L=nJs_(BE#$7_rA2Bk@#wJUM*h4RqeQm@1!LbeQzEA zPMLFVC+mOiqw+=dKR+#`bS}ND!3o~}SwlbFRlxlNy4V-all1gCYv^14-mQzz#-pyP7 z_~VMVWveUaos~Y&RWbGPM~&xmKG|G1;K{lj7AP|F_${AoHoLcS*RFMEqx&EK(6AK$qc8k_Tdru^!n&VN#d!}e z`0(x9H@z+;+v;yVzLzDs7c|(MziQHJc**AcwgidHdFkBtk1WFGJ(oKEQD;%ZL(Xu4 zwt%&nQrw$QZMtH>)3xZtx~Zu%f9*5>@G-z3C-!>O+Ay(Cf^3J@+!4Nc*~GMA`|Y)@ zy9#A)mwsfbn5e+<#4oQmGp5J`QBviz8)-uo4SG__*ZyMI{ zHBa6@aduJw1KZ)be#_&%-P`iM`g6(aueVCBm(C4aJ@wZ<^KbStd~ME?RJ<;STsB#`N^5fKhdJ!C z_e{-Zaa8csIvwO1xI*VN`%@daevminXDyrcJhJ}Z&*$wY9vfr)Q!Z0_w>uU?&! zsF7exja*hJAwuDo4yvi+Q&SJDSET-edzVA^K2@U?lB*Ja`1r032wux zYloVDYg(GmKHK!a_0jpg_xDtOemLj$?c2KxWxoFTS)9xsA*HCX>`397RjYKqH+3>{ zUR%cD;$d`tbJwB`d-P8m$?~zEmQ5`GZx=IJYkB+>C$}dnUPlFrNNzrSN#?z@LH&uP z6Z-$mn7}Xj!D)@C|Hhj+A)!;(a?hNkV#zIhyl{(_&d#~TezVUWvypfhBXhh=Cws>8 zn{vwxc+UQqFndD3mZ2Q8vwL~S_m3OqPZDm9{;=QXkK)Dc`SmuHE(eZy9t}uTz|cJ4%bq7K6Yl7Z=ak^x?FTxT^ zZ!1bTh`4%9a{2!KyVoQa&q*2k??>Nm?J_7@{A82P`8}fFKVIiem}Bibx$pSmu+>xh zjxWAs5<2gB*aJs@M}Zdw7IQ@FYh)j?GV~aTDi|j1@dynS%PXE!>{l8aJ;RgZR_Wd5 zqM|=d|DQfQzf;7BS>ll8^2}K!_4WBWkLMT{{IOHwLziySc{=BE)>fm+M;6=4LS`+qn(HTa zENI2A9jflqobMg}b+_Mp|9u-@gH8WYL(9Q&%aM?&_DCvaPx0w8J^mjH){<%4yi`m(vK>v zpD|B{@4b`VuKVw|-p$i(xt(Jc#^PM}#N+anb8BDUQd+SscWUa)mj+5EWoZc=i2AvqHs`Io$uIciSKNd*1$kjl$FL^>KF%@3th> zFeKXCxW&)?(%R^)3m=R0Z|<*$?IieF4N9LrpZ{;8M(0DJ=X0LU2o#w)@oH)9u|H2T zpS1pCV2@j+!Nsk8^5%*QmyR9skZf4^;*bJoeRyc<-o!)RJmTwTsdTnJsyo-E`1|LF zw9S^>)||3)i?5lh|5v&5G;v}|#Dx2cUbjDC`ONzN^kMm!xczm19nY_i+q+A;%`v|2 z=hDz%O}PuF7F;;k^v6q$S<-;pl*R73g#Gd6n+ZQQ>EsqLZu|7vZq<%0Rxh}dEjFkf zbG&EiJ9*vu_2=De%6HGzocFKr_BO39r{j-5<|MGKZw!+Bq!7{)ds6(PMunlojeN(8 zRb7v7*og3ZUN(6aS-V$}yY{)w`BDp+p0^*5RM>GP&GDD;&;O%n8F?R+==#sq|NRKtDf9iic3GW1{6|LU=)s1|CNG~o zb9-!&wf*+Y#@@#(zQ4bJ+q5R%-@a|DOkN-0ZV0sN zo>+G6fazb$qWv>Ut>)(R2%SHqCOZG(>}418wr>s)eXyf`)-o}189I&|WX%(|XSt@ZNT&$0DEedLek_p{CO?Iv6_V&8CvQKy*Uw9El4 z%>UuV4Ek|XCV%|-v0{s5(YNMc7pISPu4Y|IuN}o*3%`j; zS8whT@A~*)g7{-g%j5H-SE}uywDsR4`zv3+?@rEX*|D$v^Y&Lwv*TBQ z1GCdWL2fp4#69*8|2N9tIiD;a#m~0&!Tvq`2{-xc6n`J&RF~f@_kSPvztg`Nru}^& zzCm85x$;ew*q`a&8FhXi)X%a1k$k;*dHjd?d+Zy&H0m$m_o;nu`1<4W8)AQ^TQ)4^ zuVJixP``N|>;F`~gqO_m5%NFouQ|?tTpVUVg1yDDPcy#$xLtuPR8@JVYT9>3o%hTU z-KNNl?Pi)EmcaOQq)4qI(Q+K+8d`iQU0*eU7%kq&= ztG>*c$o|xO(!g!Er>6S$#BcHw@p;Hu`|Ez)X@?VEziw@v+_I}Ko9El| zD&M8z&T9QnZWmT=`18+t7t8VE>z+Rjyu|wdf9;>Y-}RPcu3EqEmzVwjKbxD%-`{(A zT)uuwm)b*KY0*CgTyFAh2lu^_(BF7BPxs4*n-f?AZP{3ExzrUd(((R1?dr13HCbIr zodJK&^7UjIF?HT)DQO8m!MNkF!Hci2uczOS>Mk