Jump to content

Official Clip Masking [REVERSED]


Recommended Posts

  • Honorable Member

This is the hidden content, please

This is the hidden content, please

You can do things like these with it:

Spoiler

 

Spoiler

 

Spoiler

.gif

 

  • Reversed from 22.2.7.0 Official Binary.
  • Experimental: Contains the modifications that I added that are not in the official.
Edited by Mali
  • Metin2 Dev 297
  • Eyes 2
  • Facepalm 1
  • Angry 1
  • Scream 1
  • Good 56
  • Love 6
  • Love 214

 

Link to comment
Share on other sites

  • Premium

Here is a little collab for the clipping, this extends the ExpandedImageBox, so you can scale/rotate those images and still be able to clip them. The code contains very informative comments so if you want to learn a few tricks you might want to read them.

Spoiler

In GrpExpandedImageInstance.cpp replace the whole Render function with this:

void CGraphicExpandedImageInstance::OnRender(RECT* rMask)
{
	// Okay so first we are gonna rework the code to use transofrmation matrix.
	// To do that we just have to touch the xyzs. This means we have to setup
	// them to match the original rectangle (without scaling rotation translation).
	// Just like how we would want to render the image to the left top corner
	// of the screen as it is in the file.
	// 
	// We will obviously need the UVs so I'm not gonna touch that part, it has
	// nothing to do with the transformation matrix.
	//
	// The only thing is that the rotation and scaling is virtual so other codes 
	// will not see the rect of the scaled/rotated eximagebox correctly so if you 
	// want to put another image on such eximageboxes you will need extra logic,
	// perhabs the current structure for clipping will not be enough for that anyway.
	//
	// With the DEBUG_CLIPMASK macro you can highlight the parent window's rect.


	CGraphicImage* pImage = m_roImage.GetPointer();
	CGraphicTexture* pTexture = pImage->GetTexturePointer();

	const RECT& c_rRect = pImage->GetRectReference();
	float texReverseWidth = 1.0f / float(pTexture->GetWidth());
	float texReverseHeight = 1.0f / float(pTexture->GetHeight());
	float su = (c_rRect.left - m_RenderingRect.left) * texReverseWidth;
	float sv = (c_rRect.top - m_RenderingRect.top) * texReverseHeight;
	float eu = (c_rRect.left + m_RenderingRect.right + (c_rRect.right - c_rRect.left)) * texReverseWidth;
	float ev = (c_rRect.top + m_RenderingRect.bottom + (c_rRect.bottom - c_rRect.top)) * texReverseHeight;

	// set up the vertex position in screen coordinates
	// the rendering rect is usually 0, only used for stuff like hp bar, 
	// normal window base and so on, where you want to replicate the texture
	// multiple times (aka. wrap texture address mode). Since it will count
	// as the "part of the basic image box" we will add it here as well.
	//
	// The only trick we will apply that we will shift the wrapping to the 
	// end positions instead of substracting them from the start positions,
	// since we want to base the original box to 0,0. We will adjust it on
	// the translation.
	float sx = 0.f;
	float sy = 0.f;
	float ex = float(pImage->GetWidth()) + m_RenderingRect.right + m_RenderingRect.left;
	float ey = float(pImage->GetHeight()) + m_RenderingRect.bottom + m_RenderingRect.top;

	TPDTVertex vertices[4];
	vertices[0].position.x = sx;
	vertices[0].position.y = sy;
	vertices[0].position.z = 0.0f;
	vertices[0].texCoord = TTextureCoordinate(su, sv);
	vertices[0].diffuse = m_DiffuseColor;

	vertices[1].position.x = ex;
	vertices[1].position.y = sy;
	vertices[1].position.z = 0.0f;
	vertices[1].texCoord = TTextureCoordinate(eu, sv);
	vertices[1].diffuse = m_DiffuseColor;

	vertices[2].position.x = sx;
	vertices[2].position.y = ey;
	vertices[2].position.z = 0.0f;
	vertices[2].texCoord = TTextureCoordinate(su, ev);
	vertices[2].diffuse = m_DiffuseColor;

	vertices[3].position.x = ex;
	vertices[3].position.y = ey;
	vertices[3].position.z = 0.0f;
	vertices[3].texCoord = TTextureCoordinate(eu, ev);
	vertices[3].diffuse = m_DiffuseColor;

	// Now we are going to apply a transformation matrix that will
	// rotate/scale/transpose the vertices to the correct position.
	//
	// We can do it 2 different ways, either set up a world transform
	// so the GPU will do this for us for every vertex we stream to it,
	// or we can directly apply it here CPU side.
	// Since we have very few (4) vertices its better to do it here 
	// since changing device states comes with some overhead, so its 
	// better to do that only when its absolutely necessary or when
	// we can spare some cpu cycles by sending the work to the GPU.

	D3DXMATRIX transform, mTemp;
	D3DXMatrixScaling(&transform, m_v2Scale.x, m_v2Scale.y, 1.f);
	D3DXMatrixTranslation(&mTemp, -(ex - sx) / 2.f, -(ey - sy) / 2.f, 0.f);
	transform *= mTemp;
	D3DXMatrixRotationZ(&mTemp, D3DXToRadian(m_fRotation));
	transform *= mTemp;
	D3DXMatrixTranslation(&mTemp, (ex - sx) / 2.f, (ey - sy) / 2.f, 0.f);
	transform *= mTemp;
	D3DXMatrixTranslation(&mTemp, m_v2Position.x - m_RenderingRect.left, m_v2Position.y - m_RenderingRect.top, 0.f);
	transform *= mTemp;

	for (size_t i = 0; i < 4; ++i)
	{
		const D3DXVECTOR2 pos(vertices[i].position.x, vertices[i].position.y);
		D3DXVECTOR4 out;
		D3DXVec2Transform(&out, &pos, &transform);
		vertices[i].position.x = out.x - 0.5f;
		vertices[i].position.y = out.y - 0.5f;
	}

	switch (m_iRenderingMode)
	{
	case RENDERING_MODE_SCREEN:
	case RENDERING_MODE_COLOR_DODGE:
		STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR);
		STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
		break;
	case RENDERING_MODE_MODULATE:
		STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
		STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
		break;
	}

	// Since dx8 doesn't have clipping, we have to apply a bit of trickery here.
	// We are going to use stenciling. This requires to have space for stencil
	// information in the depth buffer, so you will need to ask the game to
	// create an appropriate depth buffer, by changing m_dwMinStencilBits to 1
	// in D3D_CDeviceInfo::FindDepthStencilFormat.
	// Stencil buffer will store a custom value on every position you render to
	// and you can later compare it when rendering something else to drop specific
	// pixels to achieve various effects.
	// With this method it is possible to later extend the functionality since 
	// you can basically clip any shape not just rectangle like with dx9 clipping.
	// This can be useful when your parent window is a rotated exImageBox and you
	// want to clip inside it.
	if (rMask)
	{
		// First of all we will draw a rectangle equal to the size of the parent
		// window's size. We don't need any texture pos or colour, so SPVertex
		// struct would be enough but I cba creating funcs for it so just go with
		// this one.

		TPDTVertex maskVertices[4];
		maskVertices[0].position.x = float(rMask->left) - 0.5f;
		maskVertices[0].position.y = float(rMask->top) - 0.5f;
		maskVertices[0].position.z = 0.0f;

		maskVertices[1].position.x = float(rMask->right) - 0.5f;
		maskVertices[1].position.y = float(rMask->top) - 0.5f;
		maskVertices[1].position.z = 0.0f;

		maskVertices[2].position.x = float(rMask->left) - 0.5f;
		maskVertices[2].position.y = float(rMask->bottom) - 0.5f;
		maskVertices[2].position.z = 0.0f;

		maskVertices[3].position.x = float(rMask->right) - 0.5f;
		maskVertices[3].position.y = float(rMask->bottom) - 0.5f;
		maskVertices[3].position.z = 0.0f;

		// Normally nothing else uses stencil in the base game, but we will have to
		// clear the other stuff we set up in previous renders.
		STATEMANAGER.GetDevice()->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.f, 0);

		// Now enable stenciling, and make it to fail always (so this random rectangle
		// wont show up in our rendertarget).
		const DWORD zWrite = STATEMANAGER.GetRenderState(D3DRS_ZWRITEENABLE);
		STATEMANAGER.SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		STATEMANAGER.SaveRenderState(D3DRS_STENCILENABLE, TRUE);
#ifdef DEBUG_CLIPMASK
		maskVertices[0].diffuse = maskVertices[1].diffuse = maskVertices[2].diffuse = maskVertices[3].diffuse = 0x5F00FF00;
		STATEMANAGER.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
		STATEMANAGER.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
#else
		STATEMANAGER.SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
		STATEMANAGER.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER);
#endif
		STATEMANAGER.SetRenderState(D3DRS_STENCILREF, 1);

		// And now just render it just as a normal image.
		CGraphicBase::SetPDTStream(maskVertices, 4);
		CGraphicBase::SetDefaultIndexBuffer(CGraphicBase::DEFAULT_IB_FILL_RECT);

		STATEMANAGER.SetTexture(0, NULL);
		STATEMANAGER.SetTexture(1, NULL);
		STATEMANAGER.SetVertexShader(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
		STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);

		// After the render set up the stencil to only succeed on pixels we wrote 1 to.
#ifdef DEBUG_CLIPMASK
		STATEMANAGER.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
#else
		STATEMANAGER.SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
#endif
		STATEMANAGER.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);

		STATEMANAGER.SetRenderState(D3DRS_ZWRITEENABLE, zWrite);
	}

	// set up min/magfilter for scaling, instantly restore mipfilter, we don't need mips
	DWORD minF, magF, mipF;
	STATEMANAGER.GetTextureStageState(0, D3DTSS_MINFILTER, &minF);
	STATEMANAGER.GetTextureStageState(0, D3DTSS_MAGFILTER, &magF);
	STATEMANAGER.GetTextureStageState(0, D3DTSS_MIPFILTER, &mipF);
	STATEMANAGER.SetBestFiltering(0);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_MIPFILTER, mipF);

	// 2004.11.18.myevan.ctrl+alt+del ąÝşą »çżë˝Ă ƨ±â´Â ą®Á¦ 	
	if (CGraphicBase::SetPDTStream(vertices, 4))
	{
		CGraphicBase::SetDefaultIndexBuffer(CGraphicBase::DEFAULT_IB_FILL_RECT);

		STATEMANAGER.SetTexture(0, pTexture->GetD3DTexture());
		STATEMANAGER.SetTexture(1, NULL);
		STATEMANAGER.SetVertexShader(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
		STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);
	}
	//STATEMANAGER.DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, c_FillRectIndices, D3DFMT_INDEX16, vertices, sizeof(TPDTVertex));
	/////////////////////////////////////////////////////////////

	// reset filters
	STATEMANAGER.SetTextureStageState(0, D3DTSS_MINFILTER, minF);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_MAGFILTER, magF);

	// And finally disable stenciling again.
	if (rMask)
		STATEMANAGER.RestoreRenderState(D3DRS_STENCILENABLE);

	switch (m_iRenderingMode)
	{
	case RENDERING_MODE_SCREEN:
	case RENDERING_MODE_COLOR_DODGE:
	case RENDERING_MODE_MODULATE:
		STATEMANAGER.RestoreRenderState(D3DRS_SRCBLEND);
		STATEMANAGER.RestoreRenderState(D3DRS_DESTBLEND);
		break;
	}
}

In StateManager.h add this function as public to the CStateManager class:

LPDIRECT3DDEVICE8 GetDevice() { return m_lpD3DDev; }

And last in GrpDetector.cpp search for m_dwMinStencilBits and set it to 1.

 

Edited by masodikbela
fix vertex positions for masking
  • Scream 1
  • Love 12

The one and only UI programming guideline

Link to comment
Share on other sites

  • Active Member

@ DDC

Search for:

#ifdef ENABLE_EMOJI_SYSTEM
	if (m_emojiVector.empty() == false)
	{
		for(auto& rEmo : m_emojiVector)
		{
			if (rEmo.pInstance)
			{
				rEmo.pInstance->SetPosition(fStanX + rEmo.x, (fStanY + 7.0) - (rEmo.pInstance->GetHeight() / 2));
				rEmo.pInstance->Render();
			}
		}
	}
#endif

in GrpTextInstance.cpp's ::Render function and change it like that:

#ifdef ENABLE_EMOJI_SYSTEM
	if (m_emojiVector.empty() == false)
	{
		for(auto& rEmo : m_emojiVector)
		{
			if (rEmo.pInstance)
			{
				rEmo.pInstance->SetPosition(fStanX + rEmo.x, (fStanY + 7.0) - (rEmo.pInstance->GetHeight() / 2));
#if defined(__BL_CLIP_MASK__)
				if (pClipRect)
					rEmo.pInstance->Render(pClipRect);
				else
					rEmo.pInstance->Render();
#else
				rEmo.pInstance->Render();
#endif
			}
		}
	}
#endif

 

Edited by Valki
  • Metin2 Dev 1
  • Good 1
  • Love 1
Link to comment
Share on other sites

41 minutes ago, Valki said:

@ DDC

Search for:

#ifdef ENABLE_EMOJI_SYSTEM
	if (m_emojiVector.empty() == false)
	{
		for(auto& rEmo : m_emojiVector)
		{
			if (rEmo.pInstance)
			{
				rEmo.pInstance->SetPosition(fStanX + rEmo.x, (fStanY + 7.0) - (rEmo.pInstance->GetHeight() / 2));
				rEmo.pInstance->Render();
			}
		}
	}
#endif

in GrpTextInstance.cpp's ::Render function and change it like that:

#ifdef ENABLE_EMOJI_SYSTEM
	if (m_emojiVector.empty() == false)
	{
		for(auto& rEmo : m_emojiVector)
		{
			if (rEmo.pInstance)
			{
				rEmo.pInstance->SetPosition(fStanX + rEmo.x, (fStanY + 7.0) - (rEmo.pInstance->GetHeight() / 2));
#if defined(__BL_CLIP_MASK__)
				if (pClipRect)
					rEmo.pInstance->Render(pClipRect);
				else
					rEmo.pInstance->Render();
#else
				rEmo.pInstance->Render();
#endif
			}
		}
	}
#endif

 

Thank you! 

  • Love 1
Link to comment
Share on other sites

 
void CGraphicWikiRenderTargetTexture::Render() const
{
	const float sx = static_cast<float>(m_renderRect.left) - 0.5f + static_cast<float>(m_renderBox.left);
	const float sy = static_cast<float>(m_renderRect.top) - 0.5f + static_cast<float>(m_renderBox.top);
	const float ex = static_cast<float>(m_renderRect.left) + (static_cast<float>(m_renderRect.right) - static_cast<float>(m_renderRect.left)) - 0.5f - static_cast<float>(m_renderBox.right);
	const float ey = static_cast<float>(m_renderRect.top) + (static_cast<float>(m_renderRect.bottom) - static_cast<float>(m_renderRect.top)) - 0.5f - static_cast<float>(m_renderBox.bottom);
	
	const float texReverseWidth = 1.0f / (static_cast<float>(m_renderRect.right) - static_cast<float>(m_renderRect.left));
	const float texReverseHeight = 1.0f / (static_cast<float>(m_renderRect.bottom) - static_cast<float>(m_renderRect.top));
	
	const float su = m_renderBox.left * texReverseWidth;
	const float sv = m_renderBox.top * texReverseHeight;
	const float eu = ((m_renderRect.right - m_renderRect.left) - m_renderBox.right) * texReverseWidth;
	const float ev = ((m_renderRect.bottom - m_renderRect.top) - m_renderBox.bottom) * texReverseHeight;

	TPDTVertex pVertices[4];
	pVertices[0].position = TPosition(sx, sy, 0.0f);
	pVertices[0].texCoord = TTextureCoordinate(su, sv);
	pVertices[0].diffuse = 0xffffffff;
	
	pVertices[1].position = TPosition(ex, sy, 0.0f);
	pVertices[1].texCoord = TTextureCoordinate(eu, sv);
	pVertices[1].diffuse = 0xffffffff;
	
	pVertices[2].position = TPosition(sx, ey, 0.0f);
	pVertices[2].texCoord = TTextureCoordinate(su, ev);
	pVertices[2].diffuse = 0xffffffff;
	
	pVertices[3].position = TPosition(ex, ey, 0.0f);
	pVertices[3].texCoord = TTextureCoordinate(eu, ev);
	pVertices[3].diffuse = 0xffffffff;
	
	if (SetPDTStream(pVertices, 4))
	{
		CGraphicBase::SetDefaultIndexBuffer(CGraphicBase::DEFAULT_IB_FILL_RECT);
		
		STATEMANAGER.SetTexture(0, GetD3DRenderTargetTexture());
		STATEMANAGER.SetTexture(1, NULL);
		STATEMANAGER.SetVertexShader(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE);


		STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);
	}
}

I think it's wiki from AE... but only for this part, i just don't understand how to use rect,vertices and StateManager!
If you're refusing to update, i'll understand!

Edited by DDC
Link to comment
Share on other sites

  • Premium
1 hour ago, DDC said:
 
void CGraphicWikiRenderTargetTexture::Render() const
{
	const float sx = static_cast<float>(m_renderRect.left) - 0.5f + static_cast<float>(m_renderBox.left);
	const float sy = static_cast<float>(m_renderRect.top) - 0.5f + static_cast<float>(m_renderBox.top);
	const float ex = static_cast<float>(m_renderRect.left) + (static_cast<float>(m_renderRect.right) - static_cast<float>(m_renderRect.left)) - 0.5f - static_cast<float>(m_renderBox.right);
	const float ey = static_cast<float>(m_renderRect.top) + (static_cast<float>(m_renderRect.bottom) - static_cast<float>(m_renderRect.top)) - 0.5f - static_cast<float>(m_renderBox.bottom);
	
	const float texReverseWidth = 1.0f / (static_cast<float>(m_renderRect.right) - static_cast<float>(m_renderRect.left));
	const float texReverseHeight = 1.0f / (static_cast<float>(m_renderRect.bottom) - static_cast<float>(m_renderRect.top));
	
	const float su = m_renderBox.left * texReverseWidth;
	const float sv = m_renderBox.top * texReverseHeight;
	const float eu = ((m_renderRect.right - m_renderRect.left) - m_renderBox.right) * texReverseWidth;
	const float ev = ((m_renderRect.bottom - m_renderRect.top) - m_renderBox.bottom) * texReverseHeight;

	TPDTVertex pVertices[4];
	pVertices[0].position = TPosition(sx, sy, 0.0f);
	pVertices[0].texCoord = TTextureCoordinate(su, sv);
	pVertices[0].diffuse = 0xffffffff;
	
	pVertices[1].position = TPosition(ex, sy, 0.0f);
	pVertices[1].texCoord = TTextureCoordinate(eu, sv);
	pVertices[1].diffuse = 0xffffffff;
	
	pVertices[2].position = TPosition(sx, ey, 0.0f);
	pVertices[2].texCoord = TTextureCoordinate(su, ev);
	pVertices[2].diffuse = 0xffffffff;
	
	pVertices[3].position = TPosition(ex, ey, 0.0f);
	pVertices[3].texCoord = TTextureCoordinate(eu, ev);
	pVertices[3].diffuse = 0xffffffff;
	
	if (SetPDTStream(pVertices, 4))
	{
		CGraphicBase::SetDefaultIndexBuffer(CGraphicBase::DEFAULT_IB_FILL_RECT);
		
		STATEMANAGER.SetTexture(0, GetD3DRenderTargetTexture());
		STATEMANAGER.SetTexture(1, NULL);
		STATEMANAGER.SetVertexShader(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE);


		STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);
	}
}

I think it's wiki from AE... but only for this part, i just don't understand how to use rect,vertices and StateManager!
If you're refusing to update, i'll understand!

It is, and its already have clipping inside it, you can control it with the m_renderBox. The values in left, top, right and bottom of that m_renderBox will determine how much space have to be clipped from each side in pixel positions.

I made a small visual presentation about clipping, more specifically about text clipping, but the theory behind it applys to every kind of texture clipping.spacer.png

Some additional good read about texture positions and texture rendering: Texture Coordinates, Directly Mapping Texels to Pixels

Edited by Metin2 Dev
Core X - External 2 Internal
  • Metin2 Dev 1
  • Love 2

The one and only UI programming guideline

Link to comment
Share on other sites

11 hours ago, masodikbela said:

It is, and its already have clipping inside it, you can control it with the m_renderBox. The values in left, top, right and bottom of that m_renderBox will determine how much space have to be clipped from each side in pixel positions.

I made a small visual presentation about clipping, more specifically about text clipping, but the theory behind it applys to every kind of texture clipping./cdn-cgi/mirage/e4db53991da469b6fa1052b1a4756dd7bd30d12f98891bc4fbd5449b77b3370a/1280/https://metin2.download/picture/3R234sCALcAFi5iv17gBHni4vZ9dsnHj/.png?width=1437&height=740

Some additional good read about texture positions and texture rendering: Texture Coordinates, Directly Mapping Texels to Pixels

Nice tutorial! Thank you for your time! ✌️

Link to comment
Share on other sites

  • Premium

scrollowanie_masne_fest.gif

To get smooth scrolling like this in music, guild symbol selection (and maybe some custom systems you already have idk), just replace ListBoxEx class.

Spoiler

https://pastebin.com/MwRS82jG

 

class ListBoxEx(Window):
    class Item(Window):
        def __init__(self):
            Window.__init__(self)
 
        def __del__(self):
            Window.__del__(self)
 
        def SetParent(self, parent):
            Window.SetParent(self, parent)
            self.parent = proxy(parent)
 
        def OnMouseLeftButtonDown(self):
            self.parent.SelectItem(self)
 
        def OnRender(self):
            if self.parent.GetSelectedItem() == self:
                self.OnSelectedRender()
 
        def OnSelectedRender(self):
            x, y = self.GetGlobalPosition()
            grp.SetColor(grp.GenerateColor(0.0, 0.0, 0.7, 0.7))
            grp.RenderBar(x, y, self.GetWidth(), self.GetHeight())
 
    def __init__(self):
        Window.__init__(self)
 
        self.viewItemCount = 10
        self.basePos = 0
        self.itemHeight = 16
        self.itemStep = 20
        self.selItem = 0
        self.itemList = []
        self.onSelectItemEvent = lambda *arg: None
 
        if localeInfo.IsARABIC():
            self.itemWidth = 130
        else:
            self.itemWidth = 100
 
        self.scrollBar = None
        self.__UpdateSize()
 
    def __del__(self):
        Window.__del__(self)
 
    def __UpdateSize(self):
        height = self.itemStep * self.__GetViewItemCount()
 
        self.SetSize(self.itemWidth, height)
 
    def IsEmpty(self):
        if len(self.itemList) == 0:
            return 1
        return 0
 
    def SetItemStep(self, itemStep):
        self.itemStep = itemStep
        self.__UpdateSize()
 
    def SetItemSize(self, itemWidth, itemHeight):
        self.itemWidth = itemWidth
        self.itemHeight = itemHeight
        self.__UpdateSize()
 
    def SetViewItemCount(self, viewItemCount):
        self.viewItemCount = viewItemCount
 
    def SetSelectEvent(self, event):
        self.onSelectItemEvent = event
 
    def SetBasePos(self, basePos):
        if app.__BL_CLIP_MASK__:
            self.basePos = basePos
 
            curbp = self.basePos
 
            itemheight = self.itemStep * len(self.itemList)
            myheight = self.GetHeight()
 
            if itemheight < myheight:
                curbp = 0
 
            fromPos = curbp
            curPos = 0
            toPos = curbp + self.GetHeight()
            for item in self.itemList:
                if curPos + self.itemStep < fromPos or curPos > toPos:
                    item.Hide()
                else:
                    item.Show()
 
                item.SetPosition(0, curPos - fromPos)
                curPos += self.itemStep
        else:
            for oldItem in self.itemList[self.basePos:self.basePos + self.viewItemCount]:
                oldItem.Hide()
 
            self.basePos = basePos
 
            pos = basePos
            for newItem in self.itemList[self.basePos:self.basePos + self.viewItemCount]:
                (x, y) = self.GetItemViewCoord(pos, newItem.GetWidth())
                newItem.SetPosition(x, y)
                newItem.Show()
                pos += 1
 
    def GetItemIndex(self, argItem):
        return self.itemList.index(argItem)
 
    def GetSelectedItem(self):
        return self.selItem
 
    def SelectIndex(self, index):
 
        if index >= len(self.itemList) or index < 0:
            self.selItem = None
            return
 
        try:
            self.selItem = self.itemList[index]
        except:
            pass
 
    def SelectItem(self, selItem):
        self.selItem = selItem
        self.onSelectItemEvent(selItem)
 
    def RemoveAllItems(self):
        for item in self.itemList:
            item.Hide()
 
        self.selItem = None
        self.itemList = []
 
        if self.scrollBar:
            self.scrollBar.SetPos(0)
 
    def RemoveItem(self, delItem):
        if delItem == self.selItem:
            self.selItem = None
 
        self.itemList.remove(delItem)
 
    def AppendItem(self, newItem):
        newItem.SetParent(self)
        newItem.SetSize(self.itemWidth, self.itemHeight)
 
        if app.__BL_CLIP_MASK__:
            newItem.SetClippingMaskWindow(self)
 
        pos = len(self.itemList)
        if self.__IsInViewRange(pos):
            (x, y) = self.GetItemViewCoord(pos, newItem.GetWidth())
            newItem.SetPosition(x, y)
            newItem.Show()
        else:
            newItem.Hide()
 
        self.itemList.append(newItem)
 
    def SetScrollBar(self, scrollBar):
        scrollBar.SetScrollEvent(__mem_func__(self.__OnScroll))
        self.scrollBar = scrollBar
 
    def __OnScroll(self):
        if app.__BL_CLIP_MASK__:
            self.SetBasePos(int(self.scrollBar.GetPos() * (self.__GetItemCount() - 1) * self.itemStep))
        else:
            self.SetBasePos(int(self.scrollBar.GetPos() * self.__GetScrollLen()))
 
    def __GetScrollLen(self):
        scrollLen = self.__GetItemCount() - self.__GetViewItemCount()
        if scrollLen < 0:
            return 0
 
        return scrollLen
 
    def __GetViewItemCount(self):
        return self.viewItemCount
 
    def __GetItemCount(self):
        return len(self.itemList)
 
    def GetItemViewCoord(self, pos, itemWidth):
        if localeInfo.IsARABIC():
            return (self.GetWidth() - itemWidth - 10, (pos - self.basePos) * self.itemStep)
        else:
            return (0, (pos - self.basePos) * self.itemStep)
 
    def __IsInViewRange(self, pos):
        if pos < self.basePos:
            return 0
        if pos >= self.basePos + self.viewItemCount:
            return 0
        return 1

 

  • Metin2 Dev 2
  • Good 4
  • Love 5
Link to comment
Share on other sites

  • 2 weeks later...
  • 1 month later...

Thanks for release, as always a wonderful work ❤️  

I have this problem, i don t know how to explain it, but here is a gif https://metin2.download/picture/iXaXaBjXVcEa69kbPqlmOnGA3d1KV8ZP/.gif

Is there any way to make the small window inside the main window work with clipping mask? If a cancel the clipping mask for the main window, the small window work with no problem, here is a another gif https://metin2.download/picture/Lha1RPc5nAbgGnl6wU9GYJ26uE09HP73/.gif

So.. this is how it should work? Or am I using it wrong? 

Edited by Metin2 Dev
Core X - External 2 Internal
  • Metin2 Dev 2
Link to comment
Share on other sites

  • Honorable Member
10 hours ago, m2mandi said:

Thanks for release, as always a wonderful work ❤️  

I have this problem, i don t know how to explain it, but here is a gif https://metin2.download/picture/iXaXaBjXVcEa69kbPqlmOnGA3d1KV8ZP/.gif

Is there any way to make the small window inside the main window work with clipping mask? If a cancel the clipping mask for the main window, the small window work with no problem, here is a another gif https://metin2.download/picture/Lha1RPc5nAbgGnl6wU9GYJ26uE09HP73/.gif

So.. this is how it should work? Or am I using it wrong? 

This system do not support what you are trying to do. You need to make some changes

  • Good 1

 

Link to comment
Share on other sites

  • 1 month later...

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.