Jump to content

Official Clip Masking [REVERSED]


Recommended Posts

  • Active Member
On 2/25/2023 at 11:27 PM, Lima said:

dumb question here, how do you @ Mali get to have the client open and the live editing on vstudio? i cant find the option to get the proccess [10804] Metin2Debug.exe

I am new to this, if there is a guide on this already, could you point it? I must admit this is a bit overwhelming to start

Change (UserInterface->Settings) your output directory to your client directory

Spoiler

spacer.png

OR copy your whole client to your output directory (i prefer this one), then

spacer.png

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

  • 2 weeks later...
  • Honorable Member

#Update:

[AE] Whisper Window Fix: This is an official fix not experimental. I've had it for a very, very long time but I couldn't find an Arab to test it. Then I asked @ martysama0134 to test it.

Before:

Spoiler

.png

After:

Spoiler

.png

  • Metin2 Dev 1
  • Good 2
  • Love 2

 

Link to comment
Share on other sites

On 4/11/2023 at 4:30 PM, ATAG said:

Change (UserInterface->Settings) your output directory to your client directory

  Hide contents

spacer.png

OR copy your whole client to your output directory (i prefer this one), then

spacer.png

or set the debug folder

571YTnW.png

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

  • 4 months later...
  • 3 months later...

I am using the experimental version of this system together with your __BL_ENABLE_PICKUP_ITEM_EFFECT__ system. In PythonSlotWindow.cpp, 

This part:
 

		if (m_pSlotActiveEffect)
			m_pSlotActiveEffect->SetClippingMaskRect(m_rMaskRect);

Is not compatible with your __BL_ENABLE_PICKUP_ITEM_EFFECT__ system and it doesn't let client build. Because of this in PythonSlotWindow.h:

 

#if defined(__BL_ENABLE_PICKUP_ITEM_EFFECT__)
			CAniImageBox* m_pSlotActiveEffect[SLOT_ACTIVE_EFFECT_COUNT];
#else
			CAniImageBox* m_pSlotActiveEffect;
#endif


So copying from another if statement from your __BL_ENABLE_PICKUP_ITEM_EFFECT__  system, I edited the first code as such:

 

#if defined(__BL_ENABLE_PICKUP_ITEM_EFFECT__)
		for (int i = 0; i < SLOT_ACTIVE_EFFECT_COUNT; i++)
		{
			if (m_pSlotActiveEffect[i])
				m_pSlotActiveEffect[i]->SetClippingMaskRect(m_rMaskRect);
		}
#else
		if (m_pSlotActiveEffect)
			m_pSlotActiveEffect->SetClippingMaskRect(m_rMaskRect);
#endif


I could compile the Client after this. Did I mess something up or does this make sense? 

Edited by Debloat
Link to comment
Share on other sites

  • 2 months later...
  • Active+ Member

Can someone show me an example usage?
How should we adapt it to other windows?
For example, the task list.(in character window -> quest)

On 12/28/2022 at 2:19 PM, filipw1 said:

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.

  Reveal hidden contents

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

 

Not working. As you show, the sliding process does not occur, there is visual distortion.

Edited by blaxis
Link to comment
Share on other sites

  • 2 months later...
On 12/16/2022 at 10:45 PM, masodikbela said:

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.

  Reveal hidden contents

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.

 

hi can you modify dxd9?

Link to comment
Share on other sites

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.