feat: complete native client rendering parity updates
This commit is contained in:
@@ -9,31 +9,41 @@ void CGrannyModelInstance::MakeBoundBox(TBoundBox* pBoundBox,
|
||||
D3DXVECTOR3* vtMin,
|
||||
D3DXVECTOR3* vtMax)
|
||||
{
|
||||
pBoundBox->sx = OBBMin[0] * mat[0] + OBBMin[1] * mat[4] + OBBMin[2] * mat[8] + mat[12];
|
||||
pBoundBox->sy = OBBMin[0] * mat[1] + OBBMin[1] * mat[5] + OBBMin[2] * mat[9] + mat[13];
|
||||
pBoundBox->sz = OBBMin[0] * mat[2] + OBBMin[1] * mat[6] + OBBMin[2] * mat[10] + mat[14];
|
||||
pBoundBox->sx = +10000000.0f;
|
||||
pBoundBox->sy = +10000000.0f;
|
||||
pBoundBox->sz = +10000000.0f;
|
||||
pBoundBox->ex = -10000000.0f;
|
||||
pBoundBox->ey = -10000000.0f;
|
||||
pBoundBox->ez = -10000000.0f;
|
||||
|
||||
pBoundBox->ex = OBBMax[0] * mat[0] + OBBMax[1] * mat[4] + OBBMax[2] * mat[8] + mat[12];
|
||||
pBoundBox->ey = OBBMax[0] * mat[1] + OBBMax[1] * mat[5] + OBBMax[2] * mat[9] + mat[13];
|
||||
pBoundBox->ez = OBBMax[0] * mat[2] + OBBMax[1] * mat[6] + OBBMax[2] * mat[10] + mat[14];
|
||||
for (int c = 0; c < 8; ++c)
|
||||
{
|
||||
const float ox = (c & 1) ? OBBMax[0] : OBBMin[0];
|
||||
const float oy = (c & 2) ? OBBMax[1] : OBBMin[1];
|
||||
const float oz = (c & 4) ? OBBMax[2] : OBBMin[2];
|
||||
const float tx = ox * mat[0] + oy * mat[4] + oz * mat[8] + mat[12];
|
||||
const float ty = ox * mat[1] + oy * mat[5] + oz * mat[9] + mat[13];
|
||||
const float tz = ox * mat[2] + oy * mat[6] + oz * mat[10] + mat[14];
|
||||
|
||||
pBoundBox->sx = min(pBoundBox->sx, tx);
|
||||
pBoundBox->sy = min(pBoundBox->sy, ty);
|
||||
pBoundBox->sz = min(pBoundBox->sz, tz);
|
||||
pBoundBox->ex = max(pBoundBox->ex, tx);
|
||||
pBoundBox->ey = max(pBoundBox->ey, ty);
|
||||
pBoundBox->ez = max(pBoundBox->ez, tz);
|
||||
}
|
||||
|
||||
vtMin->x = min(vtMin->x, pBoundBox->sx);
|
||||
vtMin->x = min(vtMin->x, pBoundBox->ex);
|
||||
vtMin->y = min(vtMin->y, pBoundBox->sy);
|
||||
vtMin->y = min(vtMin->y, pBoundBox->ey);
|
||||
vtMin->z = min(vtMin->z, pBoundBox->sz);
|
||||
vtMin->z = min(vtMin->z, pBoundBox->ez);
|
||||
|
||||
vtMax->x = max(vtMax->x, pBoundBox->sx);
|
||||
vtMax->x = max(vtMax->x, pBoundBox->ex);
|
||||
vtMax->y = max(vtMax->y, pBoundBox->sy);
|
||||
vtMax->y = max(vtMax->y, pBoundBox->ey);
|
||||
vtMax->z = max(vtMax->z, pBoundBox->sz);
|
||||
vtMax->z = max(vtMax->z, pBoundBox->ez);
|
||||
}
|
||||
|
||||
bool CGrannyModelInstance::Intersect(const D3DXMATRIX * c_pMatrix,
|
||||
float * /*pu*/, float * /*pv*/, float * pt)
|
||||
float * pu, float * pv, float * pt)
|
||||
{
|
||||
if (!m_pgrnModelInstance)
|
||||
return false;
|
||||
@@ -88,7 +98,51 @@ bool CGrannyModelInstance::Intersect(const D3DXMATRIX * c_pMatrix,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool hasVolumeBone = false;
|
||||
for (int m = 0; m < meshCount; ++m)
|
||||
{
|
||||
const granny_mesh * pgrnMesh = m_pModel->GetGrannyModelPointer()->MeshBindings[m].Mesh;
|
||||
int * boneIndices = __GetMeshBoneIndices(m);
|
||||
|
||||
for (int b = 0; b < pgrnMesh->BoneBindingCount; ++b)
|
||||
{
|
||||
const granny_bone_binding& rgrnBoneBinding = pgrnMesh->BoneBindings[b];
|
||||
if (rgrnBoneBinding.OBBMin[0] >= rgrnBoneBinding.OBBMax[0] &&
|
||||
rgrnBoneBinding.OBBMin[1] >= rgrnBoneBinding.OBBMax[1] &&
|
||||
rgrnBoneBinding.OBBMin[2] >= rgrnBoneBinding.OBBMax[2])
|
||||
continue;
|
||||
|
||||
hasVolumeBone = true;
|
||||
const D3DXMATRIX * pBoneMat = (const D3DXMATRIX *)GrannyGetWorldPose4x4(__GetWorldPosePtr(), boneIndices[b]);
|
||||
D3DXMATRIX matBoneWorld;
|
||||
if (c_pMatrix)
|
||||
D3DXMatrixMultiply(&matBoneWorld, pBoneMat, c_pMatrix);
|
||||
else
|
||||
matBoneWorld = *pBoneMat;
|
||||
|
||||
if (IntersectCube(&matBoneWorld,
|
||||
rgrnBoneBinding.OBBMin[0], rgrnBoneBinding.OBBMin[1], rgrnBoneBinding.OBBMin[2],
|
||||
rgrnBoneBinding.OBBMax[0], rgrnBoneBinding.OBBMax[1], rgrnBoneBinding.OBBMax[2],
|
||||
ms_vtPickRayOrig, ms_vtPickRayDir,
|
||||
&u, &v, &t))
|
||||
{
|
||||
if (pu) *pu = u;
|
||||
if (pv) *pv = v;
|
||||
if (pt) *pt = t;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasVolumeBone)
|
||||
{
|
||||
if (pu) *pu = u;
|
||||
if (pv) *pv = v;
|
||||
if (pt) *pt = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
/*
|
||||
TBoundBox* boundBoxs = s_boundBoxPool.base();
|
||||
|
||||
@@ -92,7 +92,16 @@ void CCamera::Wheel(int nLen)
|
||||
if (IsLock())
|
||||
return;
|
||||
|
||||
m_v3AngularVelocity.y = (float)(nLen) * m_fResistance;
|
||||
float fAdd = (float)(nLen) * m_fResistance;
|
||||
if ((m_v3AngularVelocity.y > 0.0f && fAdd < 0.0f) || (m_v3AngularVelocity.y < 0.0f && fAdd > 0.0f))
|
||||
m_v3AngularVelocity.y = fAdd;
|
||||
else
|
||||
m_v3AngularVelocity.y += fAdd;
|
||||
|
||||
if (m_v3AngularVelocity.y > 500.0f)
|
||||
m_v3AngularVelocity.y = 500.0f;
|
||||
else if (m_v3AngularVelocity.y < -500.0f)
|
||||
m_v3AngularVelocity.y = -500.0f;
|
||||
}
|
||||
|
||||
void CCamera::BeginDrag(int nMouseX, int nMouseY)
|
||||
@@ -167,6 +176,8 @@ bool CCamera::Drag(int nMouseX, int nMouseY, LPPOINT lpReturnPoint)
|
||||
m_v3AngularVelocity.x = fNewRotationVelocity;
|
||||
m_v3AngularVelocity.z = fNewPitchVelocity;
|
||||
|
||||
m_lMousePosX = lMouseX;
|
||||
m_lMousePosY = lMouseY;
|
||||
lpReturnPoint->x = m_lMousePosX;
|
||||
lpReturnPoint->y = m_lMousePosY;
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
#include "StdAfx.h"
|
||||
#include "CullingManager.h"
|
||||
#include "GrpObjectInstance.h"
|
||||
|
||||
//#define COUNT_SHOWING_SPHERE
|
||||
|
||||
#ifdef COUNT_SHOWING_SPHERE
|
||||
int showingcount = 0;
|
||||
#endif
|
||||
|
||||
void CCullingManager::RayTraceCallback(const Vector3d &/*p1*/, // source pos of ray
|
||||
const Vector3d &/*dir*/, // dest pos of ray
|
||||
float distance,
|
||||
const Vector3d &/*sect*/,
|
||||
SpherePack *sphere)
|
||||
{
|
||||
//if (state!=VS_OUTSIDE)
|
||||
//{
|
||||
if (m_RayFarDistance<=0.0f || m_RayFarDistance>=distance)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (sphere->IS_SPHERE)
|
||||
puts("CCullingManager::RayTraceCallback");
|
||||
#endif
|
||||
m_list.push_back((CGraphicObjectInstance *)sphere->GetUserData());
|
||||
}
|
||||
//f((CGraphicObjectInstance *)sphere->GetUserData());
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
void CCullingManager::VisibilityCallback(const Frustum &/*f*/,SpherePack *sphere,ViewState state)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (sphere->IS_SPHERE)
|
||||
puts("CCullingManager::VisibilityCallback");
|
||||
#endif
|
||||
|
||||
CGraphicObjectInstance * pInstance = (CGraphicObjectInstance*)sphere->GetUserData();
|
||||
/*if (state == VS_PARTIAL)
|
||||
{
|
||||
Vector3d v;
|
||||
float r;
|
||||
pInstance->GetBoundingSphere(v,r);
|
||||
state = f.ViewVolumeTest(v,r);
|
||||
}*/
|
||||
if (state == VS_OUTSIDE)
|
||||
{
|
||||
#ifdef COUNT_SHOWING_SPHERE
|
||||
if (pInstance->isShow())
|
||||
{
|
||||
Tracef("SH : %p ",sphere->GetUserData());
|
||||
showingcount--;
|
||||
Tracef("show size : %5d\n",showingcount);
|
||||
}
|
||||
|
||||
#endif
|
||||
pInstance->Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef COUNT_SHOWING_SPHERE
|
||||
if (!pInstance->isShow())
|
||||
{
|
||||
Tracef("HS : %p ",sphere->GetUserData());
|
||||
showingcount++;
|
||||
Tracef("show size : %5d\n",showingcount);
|
||||
}
|
||||
#endif
|
||||
pInstance->Show();
|
||||
}
|
||||
}
|
||||
|
||||
void CCullingManager::RangeTestCallback(const Vector3d &/*p*/,float /*distance*/,SpherePack *sphere,ViewState state)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (sphere->IS_SPHERE)
|
||||
puts("CCullingManager::RangeTestCallback");
|
||||
#endif
|
||||
if (state!=VS_OUTSIDE)
|
||||
{
|
||||
m_list.push_back((CGraphicObjectInstance *)sphere->GetUserData());
|
||||
//f((CGraphicObjectInstance *)sphere->GetUserData());
|
||||
}
|
||||
//assert(false && "NOT REACHED");
|
||||
}
|
||||
|
||||
void CCullingManager::Reset()
|
||||
{
|
||||
m_Factory->Reset();
|
||||
}
|
||||
|
||||
void CCullingManager::Update()
|
||||
{
|
||||
// TODO : update each object
|
||||
// ÇÏÁö¸»°í °¢ÀÚ ÇÏ°Ô ÇØº¸ÀÚ
|
||||
|
||||
//DWORD time = ELTimer_GetMSec();
|
||||
//Reset();
|
||||
|
||||
m_Factory->Process();
|
||||
//Tracef("cull update : %3d ",ELTimer_GetMSec()-time);
|
||||
}
|
||||
|
||||
void CCullingManager::Process()
|
||||
{
|
||||
//DWORD time = ELTimer_GetMSec();
|
||||
//Frustum f;
|
||||
UpdateViewMatrix();
|
||||
UpdateProjMatrix();
|
||||
BuildViewFrustum();
|
||||
m_Factory->FrustumTest(GetFrustum(), this);
|
||||
//Tracef("cull process : %3d ",ELTimer_GetMSec()-time);
|
||||
}
|
||||
|
||||
CCullingManager::CullingHandle CCullingManager::Register(CGraphicObjectInstance * obj)
|
||||
{
|
||||
assert(obj);
|
||||
#ifdef COUNT_SHOWING_SPHERE
|
||||
Tracef("CR : %p ",obj);
|
||||
showingcount++;
|
||||
Tracef("show size : %5d\n",showingcount);
|
||||
#endif
|
||||
Vector3d center;
|
||||
float radius;
|
||||
obj->GetBoundingSphere(center,radius);
|
||||
return m_Factory->AddSphere_(center,radius,obj, false);
|
||||
}
|
||||
|
||||
void CCullingManager::Unregister(CullingHandle h)
|
||||
{
|
||||
#ifdef COUNT_SHOWING_SPHERE
|
||||
if (((CGraphicObjectInstance*)h->GetUserData())->isShow())
|
||||
{
|
||||
Tracef("DE : %p ",h->GetUserData());
|
||||
showingcount--;
|
||||
Tracef("show size : %5d\n",showingcount);
|
||||
}
|
||||
#endif
|
||||
m_Factory->Remove(h);
|
||||
}
|
||||
|
||||
CCullingManager::CCullingManager()
|
||||
{
|
||||
m_Factory = new SpherePackFactory(
|
||||
10000, // maximum count
|
||||
6400, // root radius
|
||||
1600, // leaf radius
|
||||
400 // extra radius
|
||||
);
|
||||
}
|
||||
|
||||
CCullingManager::~CCullingManager()
|
||||
{
|
||||
delete m_Factory;
|
||||
}
|
||||
|
||||
void CCullingManager::FindRange(const Vector3d &p, float radius)
|
||||
{
|
||||
m_list.clear();
|
||||
m_Factory->RangeTest(p, radius, this);
|
||||
}
|
||||
|
||||
void CCullingManager::FindRay(const Vector3d &p1, const Vector3d &dir)
|
||||
{
|
||||
m_RayFarDistance = -1;
|
||||
m_list.clear();
|
||||
m_Factory->RayTrace(p1,dir,this);
|
||||
}
|
||||
|
||||
void CCullingManager::FindRayDistance(const Vector3d &p1, const Vector3d &dir, float distance)
|
||||
{
|
||||
m_RayFarDistance = distance;
|
||||
m_list.clear();
|
||||
m_Factory->RayTrace(p1,dir,this);
|
||||
}
|
||||
@@ -139,6 +139,10 @@ void CGraphicBase::SetBackBufferSize(UINT uWidth, UINT uHeight)
|
||||
{
|
||||
ms_d3dPresentParameter.BackBufferWidth = uWidth;
|
||||
ms_d3dPresentParameter.BackBufferHeight = uHeight;
|
||||
ms_iWidth = uWidth;
|
||||
ms_iHeight = uHeight;
|
||||
ms_Viewport.Width = uWidth;
|
||||
ms_Viewport.Height = uHeight;
|
||||
}
|
||||
|
||||
void CGraphicBase::SetDefaultIndexBuffer(UINT eDefIB)
|
||||
|
||||
@@ -723,13 +723,32 @@ namespace UI
|
||||
CWindow * pLayer = *ritor;
|
||||
CWindow * pPickedWindow = pLayer->PickWindow(x, y);
|
||||
|
||||
if (pPickedWindow != pLayer)
|
||||
if (pPickedWindow != pLayer) {
|
||||
return pPickedWindow;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CWindowManager::IsPointInsideActiveUI(long x, long y)
|
||||
{
|
||||
CWindow * pPicked = __PickWindow(x, y);
|
||||
if (!pPicked || pPicked == m_pRootWindow)
|
||||
return false;
|
||||
|
||||
CWindow * pCur = pPicked;
|
||||
while (pCur->GetParent() && pCur->GetParent() != m_pRootWindow)
|
||||
{
|
||||
pCur = pCur->GetParent();
|
||||
}
|
||||
|
||||
if (pCur && (0 == strcmp(pCur->GetName(), "GAME") || pCur == m_pRootWindow))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWindowManager::SetMousePosition(long x, long y)
|
||||
{
|
||||
if (m_iHres==0)
|
||||
@@ -760,6 +779,13 @@ namespace UI
|
||||
|
||||
SetMousePosition(x, y);
|
||||
CWindow * pPointWindow = __PickWindow(m_lMouseX, m_lMouseY);
|
||||
if (x == 470 && y == 380) {
|
||||
std::printf(">>> C++ RunMouseMove(470, 380): m_lMouse=(%ld, %ld), pPointWindow=%s (type=%s, is_show=%d)\n",
|
||||
m_lMouseX, m_lMouseY,
|
||||
pPointWindow ? pPointWindow->GetName() : "NULL",
|
||||
pPointWindow ? typeid(*pPointWindow).name() : "none",
|
||||
pPointWindow ? pPointWindow->IsShow() : 0);
|
||||
}
|
||||
|
||||
if (g_bShowOverInWindowName)
|
||||
{
|
||||
|
||||
@@ -103,6 +103,9 @@ namespace UI
|
||||
void ActivateWindow(CWindow * pWin);
|
||||
void DeactivateWindow();
|
||||
CWindow * GetActivateWindow();
|
||||
|
||||
bool IsPointInsideActiveUI(long x, long y);
|
||||
CWindow * PickWindow(long x, long y) { return __PickWindow(x, y); }
|
||||
void SetTop(CWindow * pWin);
|
||||
void SetTopUIWindow();
|
||||
void ResetCapture();
|
||||
|
||||
@@ -250,7 +250,7 @@ bool CActorInstance::IsHandMode()
|
||||
|
||||
bool CActorInstance::IsTwoHandMode()
|
||||
{
|
||||
if (CRaceMotionData::MODE_TWOHAND_SWORD==GetMotionMode())
|
||||
if (CRaceMotionData::MODE_TWOHAND_SWORD==GetMotionMode() || CRaceMotionData::MODE_HORSE_TWOHAND_SWORD==GetMotionMode())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// SphereLib.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright (C) John W. Ratcliff, 2001.
|
||||
* All rights reserved worldwide.
|
||||
*
|
||||
* This software is provided "as is" without express or implied
|
||||
* warranties. You may freely copy and compile this source into
|
||||
* applications you distribute provided that the copyright text
|
||||
* below is included in the resulting source code, for example:
|
||||
* "Portions Copyright (C) John W. Ratcliff, 2001"
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "frustum.h"
|
||||
|
||||
//#include "frustum.h"
|
||||
|
||||
/*void Frustum::Set(int x1,int y1,int x2,int y2)
|
||||
{
|
||||
mX1 = x1;
|
||||
mY1 = y1;
|
||||
mX2 = x2;
|
||||
mY2 = y2;
|
||||
}
|
||||
|
||||
*/
|
||||
ViewState Frustum::ViewVolumeTest(const Vector3d &c_v3Center,const float c_fRadius) const
|
||||
{
|
||||
if (m_bUsingSphere)
|
||||
{
|
||||
D3DXVECTOR3 v(
|
||||
c_v3Center.x-m_v3Center.x,
|
||||
c_v3Center.y-m_v3Center.y,
|
||||
c_v3Center.z-m_v3Center.z);
|
||||
|
||||
if ((c_fRadius + m_fRadius) * (c_fRadius + m_fRadius) < D3DXVec3LengthSq(&v))
|
||||
{
|
||||
return VS_OUTSIDE;
|
||||
}
|
||||
}
|
||||
|
||||
const int count=6;
|
||||
|
||||
D3DXVECTOR3 center = c_v3Center;
|
||||
//center.y *=-1;
|
||||
|
||||
int i;
|
||||
|
||||
float distance[count];
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
distance[i] = D3DXPlaneDotCoord(&m_plane[i],¢er);
|
||||
if (distance[i]<=-c_fRadius)
|
||||
return VS_OUTSIDE;
|
||||
}
|
||||
|
||||
//return VS_INSIDE;
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
if (distance[i]<=c_fRadius)
|
||||
return VS_PARTIAL;
|
||||
}
|
||||
|
||||
return VS_INSIDE;
|
||||
}
|
||||
|
||||
void Frustum::BuildViewFrustum(D3DXMATRIX & mat)
|
||||
{
|
||||
m_bUsingSphere = false;
|
||||
m_plane[0] = D3DXPLANE( mat._13, mat._23, mat._33, mat._43);
|
||||
m_plane[1] = D3DXPLANE(mat._14 - mat._13, mat._24 - mat._23, mat._34 - mat._33, mat._44 - mat._43);
|
||||
//m_plane[0] = D3DXPLANE(mat._14 + mat._13, mat._24 + mat._23, mat._34 + mat._33, mat._44 + mat._43);
|
||||
m_plane[2] = D3DXPLANE(mat._14 + mat._11, mat._24 + mat._21, mat._34 + mat._31, mat._44 + mat._41);
|
||||
m_plane[3] = D3DXPLANE(mat._14 - mat._11, mat._24 - mat._21, mat._34 - mat._31, mat._44 - mat._41);
|
||||
m_plane[4] = D3DXPLANE(mat._14 + mat._12, mat._24 + mat._22, mat._34 + mat._32, mat._44 + mat._42);
|
||||
m_plane[5] = D3DXPLANE(mat._14 - mat._12, mat._24 - mat._22, mat._34 - mat._32, mat._44 - mat._42);
|
||||
|
||||
for(int i=0;i<6;i++)
|
||||
D3DXPlaneNormalize(&m_plane[i],&m_plane[i]);
|
||||
}
|
||||
|
||||
void Frustum::BuildViewFrustum2(D3DXMATRIX & mat, float fNear, float fFar, float fFov, float fAspect, const D3DXVECTOR3 & vCamera, const D3DXVECTOR3 & vLook)
|
||||
{
|
||||
float fViewLen = fFar-fNear;
|
||||
float fH = fViewLen * tan(fFov*0.5f);
|
||||
float fW = fH*fAspect;
|
||||
D3DXVECTOR3 P(0.0f, 0.0f, fNear+fViewLen*0.5f);
|
||||
D3DXVECTOR3 Q(fW, fH, fViewLen);
|
||||
D3DXVECTOR3 PQ = P-Q;
|
||||
m_fRadius = D3DXVec3Length(&PQ);
|
||||
m_v3Center = vCamera + vLook * (fNear+fViewLen*0.5f);
|
||||
BuildViewFrustum(mat);
|
||||
m_bUsingSphere = true;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/* Copyright (C) John W. Ratcliff, 2001.
|
||||
* All rights reserved worldwide.
|
||||
*
|
||||
* This software is provided "as is" without express or implied
|
||||
* warranties. You may freely copy and compile this source into
|
||||
* applications you distribute provided that the copyright text
|
||||
* below is included in the resulting source code, for example:
|
||||
* "Portions Copyright (C) John W. Ratcliff, 2001"
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "sphere.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
bool Vector3d::IsInStaticRange() const
|
||||
{
|
||||
const float LIMIT = 3276700.0f;
|
||||
if (x<LIMIT && x>-LIMIT)
|
||||
if (y<LIMIT && y>-LIMIT)
|
||||
if (z<LIMIT && z>-LIMIT)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sphere::Set(const Vector3d ¢er, float radius)
|
||||
{
|
||||
#ifdef __STATIC_RANGE__
|
||||
assert(center.IsInStaticRange());
|
||||
#endif
|
||||
mCenter = center;
|
||||
mRadius = radius;
|
||||
mRadius2 = radius*radius;
|
||||
}
|
||||
|
||||
|
||||
//ray-sphere intersection test from Graphics Gems p.388
|
||||
// **NOTE** There is a bug in this Graphics Gem. If the origin
|
||||
// of the ray is *inside* the sphere being tested, it reports the
|
||||
// wrong intersection location. This code has a fix for the bug.
|
||||
bool Sphere::RayIntersection(const Vector3d &rayOrigin,
|
||||
const Vector3d &dir,
|
||||
Vector3d *intersect)
|
||||
{
|
||||
//notation:
|
||||
//point E = rayOrigin
|
||||
//point O = sphere center
|
||||
|
||||
Vector3d EO = mCenter - rayOrigin;
|
||||
Vector3d V = dir;
|
||||
float dist2 = EO.x*EO.x + EO.y*EO.y + EO.z * EO.z;
|
||||
// Bug Fix For Gem, if origin is *inside* the sphere, invert the
|
||||
// direction vector so that we get a valid intersection location.
|
||||
if ( dist2 < mRadius2 ) V*=-1;
|
||||
|
||||
float v = EO.Dot(V);
|
||||
|
||||
float disc = mRadius2 - (EO.Length2() - v*v);
|
||||
|
||||
if (disc > 0.0f)
|
||||
{
|
||||
|
||||
if ( intersect )
|
||||
{
|
||||
|
||||
float d = sqrtf(disc);
|
||||
|
||||
//float dist2 = rayOrigin.DistanceSq(mCenter);
|
||||
|
||||
*intersect = rayOrigin + V*(v-d);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
bool Sphere::RayIntersection(const Vector3d &rayOrigin,
|
||||
const Vector3d &V,
|
||||
float distance,
|
||||
Vector3d *intersect)
|
||||
{
|
||||
Vector3d sect;
|
||||
bool hit = RayIntersectionInFront(rayOrigin,V,§);
|
||||
|
||||
if ( hit )
|
||||
{
|
||||
float d = rayOrigin.DistanceSq(sect);
|
||||
if ( d > (distance*distance) ) return false;
|
||||
if ( intersect ) *intersect = sect;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Sphere::RayIntersectionInFront(const Vector3d &rayOrigin,
|
||||
const Vector3d &V,
|
||||
Vector3d *intersect)
|
||||
{
|
||||
Vector3d sect;
|
||||
bool hit = RayIntersection(rayOrigin,V,§);
|
||||
|
||||
if ( hit )
|
||||
{
|
||||
|
||||
Vector3d dir = sect - rayOrigin;
|
||||
|
||||
float dot = dir.Dot(V);
|
||||
|
||||
if ( dot >= 0 ) // then it's in front!
|
||||
{
|
||||
if ( intersect ) *intersect = sect;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sphere::Report(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
An Efficient Bounding Sphere
|
||||
by Jack Ritter
|
||||
from "Graphics Gems", Academic Press, 1990
|
||||
*/
|
||||
|
||||
/* Routine to calculate tight bounding sphere over */
|
||||
/* a set of points in 3D */
|
||||
/* This contains the routine find_bounding_sphere(), */
|
||||
/* the struct definition, and the globals used for parameters. */
|
||||
/* The abs() of all coordinates must be < BIGNUMBER */
|
||||
/* Code written by Jack Ritter and Lyle Rains. */
|
||||
|
||||
#define BIGNUMBER 100000000.0 /* hundred million */
|
||||
|
||||
void Sphere::Compute(const SphereInterface &source)
|
||||
{
|
||||
|
||||
Vector3d xmin,xmax,ymin,ymax,zmin,zmax,dia1,dia2;
|
||||
|
||||
/* FIRST PASS: find 6 minima/maxima points */
|
||||
xmin.Set(BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
xmax.Set(-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
ymin.Set(BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
ymax.Set(-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
zmin.Set(BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
zmax.Set(-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
|
||||
int count = source.GetVertexCount();
|
||||
|
||||
for (int i=0; i<count; i++)
|
||||
{
|
||||
Vector3d caller_p;
|
||||
source.GetVertex(i,caller_p);
|
||||
|
||||
if (caller_p.GetX()<xmin.GetX()) xmin = caller_p; /* New xminimum point */
|
||||
if (caller_p.GetX()>xmax.GetX()) xmax = caller_p;
|
||||
if (caller_p.GetY()<ymin.GetY()) ymin = caller_p;
|
||||
if (caller_p.GetY()>ymax.GetY()) ymax = caller_p;
|
||||
if (caller_p.GetZ()<zmin.GetZ()) zmin = caller_p;
|
||||
if (caller_p.GetZ()>zmax.GetZ()) zmax = caller_p;
|
||||
}
|
||||
|
||||
/* Set xspan = distance between the 2 points xmin & xmax (squared) */
|
||||
float dx = xmax.GetX() - xmin.GetX();
|
||||
float dy = xmax.GetY() - xmin.GetY();
|
||||
float dz = xmax.GetZ() - xmin.GetZ();
|
||||
float xspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
/* Same for y & z spans */
|
||||
dx = ymax.GetX() - ymin.GetX();
|
||||
dy = ymax.GetY() - ymin.GetY();
|
||||
dz = ymax.GetZ() - ymin.GetZ();
|
||||
float yspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
dx = zmax.GetX() - zmin.GetX();
|
||||
dy = zmax.GetY() - zmin.GetY();
|
||||
dz = zmax.GetZ() - zmin.GetZ();
|
||||
float zspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
/* Set points dia1 & dia2 to the maximally separated pair */
|
||||
dia1 = xmin;
|
||||
dia2 = xmax; /* assume xspan biggest */
|
||||
float maxspan = xspan;
|
||||
|
||||
if (yspan>maxspan)
|
||||
{
|
||||
maxspan = yspan;
|
||||
dia1 = ymin;
|
||||
dia2 = ymax;
|
||||
}
|
||||
|
||||
if (zspan>maxspan)
|
||||
{
|
||||
dia1 = zmin;
|
||||
dia2 = zmax;
|
||||
}
|
||||
|
||||
|
||||
/* dia1,dia2 is a diameter of initial sphere */
|
||||
/* calc initial center */
|
||||
mCenter.SetX( (dia1.GetX()+dia2.GetX())*0.5f );
|
||||
mCenter.SetY( (dia1.GetY()+dia2.GetY())*0.5f );
|
||||
mCenter.SetZ( (dia1.GetZ()+dia2.GetZ())*0.5f );
|
||||
/* calculate initial radius**2 and radius */
|
||||
dx = dia2.GetX()-mCenter.GetX(); /* x component of radius vector */
|
||||
dy = dia2.GetY()-mCenter.GetY(); /* y component of radius vector */
|
||||
dz = dia2.GetZ()-mCenter.GetZ(); /* z component of radius vector */
|
||||
mRadius2 = dx*dx + dy*dy + dz*dz;
|
||||
mRadius = float(sqrt(mRadius2));
|
||||
|
||||
/* SECOND PASS: increment current sphere */
|
||||
|
||||
for (int j=0; j<count; j++)
|
||||
{
|
||||
Vector3d caller_p;
|
||||
source.GetVertex(j,caller_p);
|
||||
dx = caller_p.GetX()-mCenter.GetX();
|
||||
dy = caller_p.GetY()-mCenter.GetY();
|
||||
dz = caller_p.GetZ()-mCenter.GetZ();
|
||||
float old_to_p_sq = dx*dx + dy*dy + dz*dz;
|
||||
if (old_to_p_sq > mRadius2) /* do r**2 test first */
|
||||
{ /* this point is outside of current sphere */
|
||||
float old_to_p = float(sqrt(old_to_p_sq));
|
||||
/* calc radius of new sphere */
|
||||
mRadius = (mRadius + old_to_p) * 0.5f;
|
||||
mRadius2 = mRadius*mRadius; /* for next r**2 compare */
|
||||
float old_to_new = old_to_p - mRadius;
|
||||
/* calc center of new sphere */
|
||||
float recip = 1.0f /old_to_p;
|
||||
|
||||
float cx = (mRadius*mCenter.GetX() + old_to_new*caller_p.GetX()) * recip;
|
||||
float cy = (mRadius*mCenter.GetY() + old_to_new*caller_p.GetY()) * recip;
|
||||
float cz = (mRadius*mCenter.GetZ() + old_to_new*caller_p.GetZ()) * recip;
|
||||
|
||||
mCenter.Set(cx,cy,cz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,878 @@
|
||||
/* Copyright (C) John W. Ratcliff, 2001.
|
||||
* All rights reserved worldwide.
|
||||
*
|
||||
* This software is provided "as is" without express or implied
|
||||
* warranties. You may freely copy and compile this source into
|
||||
* applications you distribute provided that the copyright text
|
||||
* below is included in the resulting source code, for example:
|
||||
* "Portions Copyright (C) John W. Ratcliff, 2001"
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "spherepack.h"
|
||||
|
||||
#if DEMO
|
||||
int PrintText(int x, int y, int color, char* output, ...);
|
||||
int DrawLine(int x1, int y1, int x2, int y2, int color);
|
||||
int DrawCircle(int locx, int locy, int radius, int color);
|
||||
#endif
|
||||
|
||||
SpherePackFactory::SpherePackFactory(int maxspheres, float rootsize, float leafsize, float gravy)
|
||||
{
|
||||
NANOBEGIN
|
||||
maxspheres *= 4; // include room for both trees, the root node and leaf node tree, and the superspheres
|
||||
mMaxRootSize = rootsize;
|
||||
mMaxLeafSize = leafsize;
|
||||
mSuperSphereGravy = gravy;
|
||||
mIntegrate = new SpherePackFifo(maxspheres);
|
||||
mRecompute = new SpherePackFifo(maxspheres);
|
||||
|
||||
mSpheres.Set(maxspheres); // init pool to hold all possible SpherePack instances.
|
||||
|
||||
Vector3d p(0,0,0);
|
||||
|
||||
mRoot = mSpheres.GetFreeLink(); // initially empty
|
||||
mRoot->Init(this,p,6553600,0, false);
|
||||
mRoot->SetSpherePackFlag(SpherePackFlag(SPF_SUPERSPHERE | SPF_ROOTNODE | SPF_ROOT_TREE));
|
||||
|
||||
#if DEMO
|
||||
mRoot->SetColor(0x00FFFFFF);
|
||||
#endif
|
||||
|
||||
mLeaf = mSpheres.GetFreeLink();; // initially empty
|
||||
mLeaf->Init(this,p,1638400,0,false);
|
||||
mLeaf->SetSpherePackFlag(SpherePackFlag(SPF_SUPERSPHERE | SPF_ROOTNODE | SPF_LEAF_TREE));
|
||||
|
||||
#if DEMO
|
||||
mLeaf->SetColor(0x00FFFFFF);
|
||||
mColorCount = 0;
|
||||
|
||||
mColors[0] = 0x00FF0000;
|
||||
mColors[1] = 0x0000FF00;
|
||||
mColors[2] = 0x000000FF;
|
||||
mColors[3] = 0x00FFFF00;
|
||||
mColors[4] = 0x00FF00FF;
|
||||
mColors[5] = 0x0000FFFF;
|
||||
mColors[6] = 0x00FF8080;
|
||||
mColors[7] = 0x0000FF80;
|
||||
mColors[8] = 0x000080FF;
|
||||
mColors[9] = 0x00FFFF80;
|
||||
mColors[10] = 0x00FF80FF;
|
||||
mColors[11] = 0x0080FFFF;
|
||||
|
||||
#endif
|
||||
NANOEND
|
||||
}
|
||||
|
||||
SpherePackFactory::~SpherePackFactory(void)
|
||||
{
|
||||
delete mIntegrate; // free up integration fifo
|
||||
delete mRecompute; // free up recomputation fifo.
|
||||
}
|
||||
|
||||
void SpherePackFactory::Process(void)
|
||||
{
|
||||
{
|
||||
// First recompute anybody that needs to be recomputed!!
|
||||
// When leaf node spheres exit their parent sphere, then the parent sphere needs to be rebalanced. In fact,it may now be empty and
|
||||
// need to be removed.
|
||||
// This is the location where (n) number of spheres in the recomputation FIFO are allowed to be rebalanced in the tree.
|
||||
int maxrecompute = mRecompute->GetCount();
|
||||
for (int i = 0; i < maxrecompute; ++i)
|
||||
{
|
||||
SpherePack * pack = mRecompute->Pop();
|
||||
if (!pack) break;
|
||||
pack->SetFifo1(0); // no longer on the fifo!!
|
||||
bool kill = pack->Recompute(mSuperSphereGravy);
|
||||
if (kill) Remove(pack);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Now, process the integration step.
|
||||
int maxintegrate = mIntegrate->GetCount();
|
||||
|
||||
for (int i = 0; i < maxintegrate; ++i)
|
||||
{
|
||||
SpherePack * pack = mIntegrate->Pop();
|
||||
if (!pack)
|
||||
break;
|
||||
pack->SetFifo2(0);
|
||||
|
||||
if (pack->HasSpherePackFlag(SPF_ROOT_TREE))
|
||||
Integrate(pack,mRoot,mMaxRootSize); // integrate this one single dude against the root node.
|
||||
else
|
||||
Integrate(pack,mLeaf,mMaxLeafSize); // integrate this one single dude against the root node.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
SpherePack * SpherePackFactory::AddSphere_(const Vector3d &pos,
|
||||
float radius,
|
||||
void *userdata,
|
||||
bool isSphere,
|
||||
int flags)
|
||||
{
|
||||
|
||||
SpherePack *pack = mSpheres.GetFreeLink();
|
||||
|
||||
assert(pack);
|
||||
|
||||
if (pack)
|
||||
{
|
||||
if (flags & SPF_ROOT_TREE)
|
||||
{
|
||||
pack->Init(this,pos,radius,userdata, isSphere);
|
||||
pack->SetSpherePackFlag(SPF_ROOT_TREE); // member of the leaf node tree!
|
||||
AddIntegrate(pack); // add to integration list.
|
||||
}
|
||||
else
|
||||
{
|
||||
pack->Init(this,pos,radius,userdata, isSphere);
|
||||
pack->SetSpherePackFlag(SPF_LEAF_TREE); // member of the leaf node tree!
|
||||
AddIntegrate(pack); // add to integration list.
|
||||
}
|
||||
}
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
void SpherePackFactory::AddIntegrate(SpherePack *pack)
|
||||
{
|
||||
if (pack->HasSpherePackFlag(SPF_ROOT_TREE))
|
||||
mRoot->AddChild(pack);
|
||||
else
|
||||
mLeaf->AddChild(pack);
|
||||
|
||||
pack->SetSpherePackFlag(SPF_INTEGRATE); // still needs to be integrated!
|
||||
SpherePack **fifo = mIntegrate->Push(pack); // add it to the integration stack.
|
||||
pack->SetFifo2(fifo);
|
||||
}
|
||||
|
||||
void SpherePackFactory::AddRecompute(SpherePack *recompute)
|
||||
{
|
||||
if (!recompute->HasSpherePackFlag(SPF_RECOMPUTE))
|
||||
{
|
||||
if (recompute->GetChildCount())
|
||||
{
|
||||
recompute->SetSpherePackFlag(SPF_RECOMPUTE); // needs to be recalculated!
|
||||
SpherePack **fifo = mRecompute->Push(recompute);
|
||||
recompute->SetFifo1(fifo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(recompute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::Render(void)
|
||||
{
|
||||
#if DEMO
|
||||
mRoot->Render(mRoot->GetColor());
|
||||
mLeaf->Render(mLeaf->GetColor());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SpherePack::Render(unsigned int /*color*/)
|
||||
{
|
||||
#if DEMO
|
||||
if (!HasSpherePackFlag(SPF_ROOTNODE))
|
||||
{
|
||||
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
color = mColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mParent->HasSpherePackFlag(SPF_ROOTNODE)) color = 0x00FFFFFF;
|
||||
}
|
||||
#if DEMO
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y),int(GetRadius()),color);
|
||||
#endif
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
if (HasSpherePackFlag(SPF_LEAF_TREE))
|
||||
{
|
||||
|
||||
#if DEMO
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y),int(GetRadius()),color);
|
||||
#endif
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!sphere->IS_SPHERE)
|
||||
puts("SpherePack::Render");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) GetUserData();
|
||||
|
||||
link = link->GetParent();
|
||||
|
||||
if (link && !link->HasSpherePackFlag(SPF_ROOTNODE))
|
||||
{
|
||||
DrawLine(int(mCenter.x), int(mCenter.y),
|
||||
int(link->mCenter.x), int(link->mCenter.y),
|
||||
link->GetColor());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEMO
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y),int(GetRadius())+3,color);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mChildren)
|
||||
{
|
||||
SpherePack *pack = mChildren;
|
||||
|
||||
while (pack)
|
||||
{
|
||||
pack->Render(color);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SpherePack::Recompute(float gravy)
|
||||
{
|
||||
if (!mChildren) return true; // kill it!
|
||||
if (HasSpherePackFlag(SPF_ROOTNODE)) return false; // don't recompute root nodes!
|
||||
|
||||
#if 1
|
||||
// recompute bounding sphere!
|
||||
Vector3d total(0,0,0);
|
||||
int count=0;
|
||||
SpherePack *pack = mChildren;
|
||||
while (pack)
|
||||
{
|
||||
total+=pack->mCenter;
|
||||
count++;
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
float recip = 1.0f / float(count);
|
||||
total*=recip;
|
||||
|
||||
Vector3d oldpos = mCenter;
|
||||
|
||||
#ifdef __STATIC_RANGE__
|
||||
assert(total.IsInStaticRange());
|
||||
#endif
|
||||
mCenter = total; // new origin!
|
||||
float maxradius = 0;
|
||||
|
||||
pack = mChildren;
|
||||
|
||||
while (pack)
|
||||
{
|
||||
float dist = DistanceSquared(pack);
|
||||
float radius = sqrtf(dist) + pack->GetRadius();
|
||||
if (radius > maxradius)
|
||||
{
|
||||
maxradius = radius;
|
||||
if ((maxradius+gravy) >= GetRadius())
|
||||
{
|
||||
#ifdef __STATIC_RANGE__
|
||||
assert(oldpos.IsInStaticRange());
|
||||
#endif
|
||||
mCenter = oldpos;
|
||||
ClearSpherePackFlag(SPF_RECOMPUTE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
maxradius+=gravy;
|
||||
|
||||
SetRadius(maxradius);
|
||||
|
||||
// now all children have to recompute binding distance!!
|
||||
pack = mChildren;
|
||||
|
||||
while (pack)
|
||||
{
|
||||
pack->ComputeBindingDistance(this);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ClearSpherePackFlag(SPF_RECOMPUTE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SpherePack::LostChild(SpherePack *t)
|
||||
{
|
||||
assert(mChildCount);
|
||||
assert(mChildren);
|
||||
|
||||
#ifdef _DEBUG // debug validation code.
|
||||
|
||||
SpherePack *pack = mChildren;
|
||||
bool found = false;
|
||||
while (pack)
|
||||
{
|
||||
if (pack == t)
|
||||
{
|
||||
assert(!found);
|
||||
found = true;
|
||||
}
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
assert(found);
|
||||
|
||||
#endif
|
||||
|
||||
// first patch old linked list.. his previous now points to his next
|
||||
SpherePack *prev = t->_GetPrevSibling();
|
||||
|
||||
if (prev)
|
||||
{
|
||||
SpherePack *next = t->_GetNextSibling();
|
||||
prev->SetNextSibling(next); // my previous now points to my next
|
||||
if (next) next->SetPrevSibling(prev);
|
||||
// list is patched!
|
||||
}
|
||||
else
|
||||
{
|
||||
SpherePack *next = t->_GetNextSibling();
|
||||
mChildren = next;
|
||||
if (mChildren) mChildren->SetPrevSibling(0);
|
||||
}
|
||||
|
||||
mChildCount--;
|
||||
|
||||
if (!mChildCount && HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
mFactory->Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::Remove(SpherePack*pack)
|
||||
{
|
||||
|
||||
if (pack->HasSpherePackFlag(SPF_ROOTNODE)) return; // CAN NEVER REMOVE THE ROOT NODE EVER!!!
|
||||
|
||||
if (pack->HasSpherePackFlag(SPF_SUPERSPHERE) && pack->HasSpherePackFlag(SPF_LEAF_TREE))
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!pack->IS_SPHERE)
|
||||
puts("SpherePackFactory::Remove");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) pack->GetUserData();
|
||||
|
||||
Remove(link);
|
||||
}
|
||||
|
||||
pack->Unlink();
|
||||
|
||||
mSpheres.Release(pack);
|
||||
}
|
||||
|
||||
#if DEMO
|
||||
unsigned int SpherePackFactory::GetColor(void)
|
||||
{
|
||||
unsigned int ret = mColors[mColorCount];
|
||||
mColorCount++;
|
||||
if (mColorCount == MAXCOLORS) mColorCount = 0;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SpherePackFactory::Integrate(SpherePack *pack,
|
||||
SpherePack *supersphere,
|
||||
float node_size)
|
||||
{
|
||||
// ok..time to integrate this sphere with the tree
|
||||
// first find which supersphere we are closest to the center of
|
||||
|
||||
SpherePack *search = supersphere->GetChildren();
|
||||
|
||||
SpherePack *nearest1 = 0; // nearest supersphere we are completely
|
||||
float neardist1 = 1e38f; // enclosed within
|
||||
|
||||
SpherePack *nearest2 = 0; // supersphere we must grow the least to
|
||||
float neardist2 = 1e38f; // add ourselves to.
|
||||
|
||||
//int scount = 1;
|
||||
|
||||
while (search)
|
||||
{
|
||||
if (search->HasSpherePackFlag(SPF_SUPERSPHERE) && !search->HasSpherePackFlag(SPF_ROOTNODE) && search->GetChildCount())
|
||||
{
|
||||
|
||||
float dist = pack->DistanceSquared(search);
|
||||
|
||||
if (nearest1)
|
||||
{
|
||||
if (dist < neardist1)
|
||||
{
|
||||
|
||||
float d = sqrtf(dist)+pack->GetRadius();
|
||||
|
||||
if (d <= search->GetRadius())
|
||||
{
|
||||
neardist1 = dist;
|
||||
nearest1 = search;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
float d = (sqrtf(dist) + pack->GetRadius())-search->GetRadius();
|
||||
|
||||
if (d < neardist2)
|
||||
{
|
||||
if (d < 0)
|
||||
{
|
||||
neardist1 = dist;
|
||||
nearest1 = search;
|
||||
}
|
||||
else
|
||||
{
|
||||
neardist2 = d;
|
||||
nearest2 = search;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
search = search->_GetNextSibling();
|
||||
}
|
||||
|
||||
// ok...now..on exit let's see what we got.
|
||||
if (nearest1)
|
||||
{
|
||||
// if we are inside an existing supersphere, we are all good!
|
||||
// we need to detach item from wherever it is, and then add it to
|
||||
// this supersphere as a child.
|
||||
pack->Unlink();
|
||||
nearest1->AddChild(pack);
|
||||
pack->ComputeBindingDistance(nearest1);
|
||||
nearest1->Recompute(mSuperSphereGravy);
|
||||
|
||||
if (nearest1->HasSpherePackFlag(SPF_LEAF_TREE))
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!nearest1->IS_SPHERE)
|
||||
puts("SpherePackFactory::Integrate1");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) nearest1->GetUserData();
|
||||
link->NewPosRadius(nearest1->GetPos(), nearest1->GetRadius());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool newsphere = true;
|
||||
|
||||
if (nearest2)
|
||||
{
|
||||
float newsize = neardist2 + nearest2->GetRadius() + mSuperSphereGravy;
|
||||
|
||||
if (newsize <= node_size)
|
||||
{
|
||||
pack->Unlink();
|
||||
|
||||
nearest2->SetRadius(newsize);
|
||||
nearest2->AddChild(pack);
|
||||
nearest2->Recompute(mSuperSphereGravy);
|
||||
pack->ComputeBindingDistance(nearest2);
|
||||
|
||||
if (nearest2->HasSpherePackFlag(SPF_LEAF_TREE))
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!nearest2->IS_SPHERE)
|
||||
puts("SpherePackFactory::Integrate2");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) nearest2->GetUserData();
|
||||
link->NewPosRadius(nearest2->GetPos(), nearest2->GetRadius());
|
||||
}
|
||||
|
||||
newsphere = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (newsphere)
|
||||
{
|
||||
assert(supersphere->HasSpherePackFlag(SPF_ROOTNODE));
|
||||
// we are going to create a new superesphere around this guy!
|
||||
pack->Unlink();
|
||||
|
||||
SpherePack *parent = mSpheres.GetFreeLink();
|
||||
assert(parent);
|
||||
parent->Init(this, pack->GetPos(), pack->GetRadius()+mSuperSphereGravy, 0, false);
|
||||
|
||||
if (supersphere->HasSpherePackFlag(SPF_ROOT_TREE))
|
||||
parent->SetSpherePackFlag(SPF_ROOT_TREE);
|
||||
else
|
||||
parent->SetSpherePackFlag(SPF_LEAF_TREE);
|
||||
|
||||
parent->SetSpherePackFlag(SPF_SUPERSPHERE);
|
||||
#if DEMO
|
||||
parent->SetColor(GetColor());
|
||||
#endif
|
||||
parent->AddChild(pack);
|
||||
|
||||
supersphere->AddChild(parent);
|
||||
|
||||
parent->Recompute(mSuperSphereGravy);
|
||||
pack->ComputeBindingDistance(parent);
|
||||
|
||||
if (parent->HasSpherePackFlag(SPF_LEAF_TREE))
|
||||
{
|
||||
// need to create parent association!
|
||||
SpherePack *link = AddSphere_(parent->GetPos(), parent->GetRadius(), parent, true, SPF_ROOT_TREE);
|
||||
parent->SetUserData(link, true); // hook him up!!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pack->ClearSpherePackFlag(SPF_INTEGRATE); // we've been integrated!
|
||||
}
|
||||
|
||||
|
||||
void SpherePackFactory::FrustumTest(const Frustum &f,SpherePackCallback *callback)
|
||||
{
|
||||
// test case here, just traverse children.
|
||||
mCallback = callback;
|
||||
mRoot->VisibilityTest(f,this,VS_PARTIAL);
|
||||
}
|
||||
|
||||
|
||||
void SpherePack::VisibilityTest(const Frustum &f,SpherePackCallback *callback,ViewState state)
|
||||
{
|
||||
|
||||
if (state == VS_PARTIAL)
|
||||
{
|
||||
state = f.ViewVolumeTest(mCenter, GetRadius());
|
||||
#if DEMO
|
||||
if (state != VS_OUTSIDE)
|
||||
{
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y), int(GetRadius()), 0x404040);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
|
||||
|
||||
if (state == VS_OUTSIDE)
|
||||
{
|
||||
if (HasSpherePackFlag(SPF_HIDDEN)) return; // no state change
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_INSIDE | SPF_PARTIAL));
|
||||
SetSpherePackFlag(SPF_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == VS_INSIDE)
|
||||
{
|
||||
if (HasSpherePackFlag(SPF_INSIDE)) return; // no state change
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_PARTIAL | SPF_HIDDEN));
|
||||
SetSpherePackFlag(SPF_INSIDE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_HIDDEN | SPF_INSIDE));
|
||||
SetSpherePackFlag(SPF_PARTIAL);
|
||||
}
|
||||
}
|
||||
|
||||
SpherePack *pack = mChildren;
|
||||
|
||||
while (pack)
|
||||
{
|
||||
pack->VisibilityTest(f,callback,state);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case VS_INSIDE:
|
||||
if (!HasSpherePackFlag(SPF_INSIDE))
|
||||
{
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_HIDDEN | SPF_PARTIAL));
|
||||
SetSpherePackFlag(SPF_INSIDE);
|
||||
callback->VisibilityCallback(f,this,state);
|
||||
}
|
||||
break;
|
||||
case VS_OUTSIDE:
|
||||
if (!HasSpherePackFlag(SPF_HIDDEN))
|
||||
{
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_INSIDE | SPF_PARTIAL));
|
||||
SetSpherePackFlag(SPF_HIDDEN);
|
||||
callback->VisibilityCallback(f,this,state);
|
||||
}
|
||||
break;
|
||||
case VS_PARTIAL:
|
||||
//if (!HasSpherePackFlag(SPF_PARTIAL))
|
||||
{
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_INSIDE | SPF_HIDDEN));
|
||||
SetSpherePackFlag(SPF_PARTIAL);
|
||||
callback->VisibilityCallback(f,this,state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::RayTrace(const Vector3d &p1,
|
||||
const Vector3d &p2,
|
||||
SpherePackCallback *callback)
|
||||
{
|
||||
// test case here, just traverse children.
|
||||
Vector3d dir = p2;
|
||||
float dist = dir.Normalize();
|
||||
mCallback = callback;
|
||||
mRoot->RayTrace(p1,dir,dist,this);
|
||||
}
|
||||
|
||||
#include "../EterBase/Debug.h"
|
||||
|
||||
void SpherePackFactory::RangeTest(const Vector3d ¢er,float radius,SpherePackCallback *callback)
|
||||
{
|
||||
#ifdef __STATIC_RANGE__
|
||||
if (!center.IsInStaticRange())
|
||||
{
|
||||
TraceError("SpherePackFactory::RangeTest - RANGE ERROR %f, %f, %f",
|
||||
center.x, center.y, center.z);
|
||||
assert("SpherePackFactory::RangeTest - RANGE ERROR");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mCallback = callback;
|
||||
mRoot->RangeTest(center,radius,this,VS_PARTIAL);
|
||||
}
|
||||
|
||||
void SpherePackFactory::PointTest2d(const Vector3d ¢er, SpherePackCallback *callback)
|
||||
{
|
||||
#ifdef __STATIC_RANGE__
|
||||
if (!center.IsInStaticRange())
|
||||
{
|
||||
TraceError("SpherePackFactory::RangeTest2d - RANGE ERROR %f, %f, %f",
|
||||
center.x, center.y, center.z);
|
||||
assert("SpherePackFactory::RangeTest2d - RANGE ERROR");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mCallback = callback;
|
||||
|
||||
#ifdef SPHERELIB_STRICT
|
||||
mRoot->PointTest2d(center, this,VS_PARTIAL);
|
||||
extern bool MAPOUTDOOR_GET_HEIGHT_TRACE;
|
||||
if (MAPOUTDOOR_GET_HEIGHT_TRACE)
|
||||
puts("================================================");
|
||||
#else
|
||||
mRoot->PointTest2d(center, this,VS_PARTIAL);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void SpherePack::RangeTest(const Vector3d &p,
|
||||
float distance,
|
||||
SpherePackCallback *callback,
|
||||
ViewState state)
|
||||
{
|
||||
|
||||
if (state == VS_PARTIAL)
|
||||
{
|
||||
float d = p.Distance(mCenter);
|
||||
if ((d-distance) > GetRadius()) return;;
|
||||
if ((GetRadius()+d) < distance) state = VS_INSIDE;
|
||||
}
|
||||
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
#if DEMO
|
||||
if (state == VS_PARTIAL)
|
||||
{
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y), int(GetRadius()), 0x404040);
|
||||
}
|
||||
#endif
|
||||
SpherePack *pack = mChildren;
|
||||
while (pack)
|
||||
{
|
||||
pack->RangeTest(p,distance,callback,state);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
callback->RangeTestCallback(p,distance,this,state);
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePack::PointTest2d(const Vector3d &p,
|
||||
SpherePackCallback *callback,
|
||||
ViewState state)
|
||||
{
|
||||
if (state == VS_PARTIAL)
|
||||
{
|
||||
float dx=p.x-mCenter.x;
|
||||
float dy=p.y-mCenter.y;
|
||||
float distSquare = (dx*dx)+(dy*dy);
|
||||
|
||||
if (distSquare > GetRadius2()) return;;
|
||||
if (GetRadius2() < -distSquare) state = VS_INSIDE;
|
||||
}
|
||||
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
#if DEMO
|
||||
if (state == VS_PARTIAL)
|
||||
{
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y), int(GetRadius()), 0x404040);
|
||||
}
|
||||
#endif
|
||||
SpherePack *pack = mChildren;
|
||||
while (pack)
|
||||
{
|
||||
pack->PointTest2d(p, callback, state);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
extern bool MAPOUTDOOR_GET_HEIGHT_TRACE;
|
||||
if (MAPOUTDOOR_GET_HEIGHT_TRACE)
|
||||
{
|
||||
float dx=p.x-mCenter.x;
|
||||
float dy=p.y-mCenter.y;
|
||||
float distSquare = (dx*dx)+(dy*dy);
|
||||
printf("--- (%f, %f) dist %f radius %f isSphere %d\n", mCenter.x, mCenter.y, distSquare, GetRadius(), IS_SPHERE);
|
||||
}
|
||||
#endif
|
||||
callback->PointTest2dCallback(p, this, state);
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::RangeTestCallback(const Vector3d &p,float distance,SpherePack *sphere,ViewState state)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!sphere->IS_SPHERE)
|
||||
puts("SpherePackFactory::RangeTestCallback");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) sphere->GetUserData();
|
||||
if (link) link->RangeTest(p,distance,mCallback,state);
|
||||
};
|
||||
|
||||
void SpherePackFactory::PointTest2dCallback(const Vector3d &p, SpherePack *sphere,ViewState state)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!sphere->IS_SPHERE)
|
||||
puts("SpherePackFactory::PointTest2dCallback");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) sphere->GetUserData();
|
||||
if (link) link->PointTest2d(p, mCallback,state);
|
||||
};
|
||||
|
||||
void SpherePack::RayTrace(const Vector3d &p1,
|
||||
const Vector3d &dir,
|
||||
float distance,
|
||||
SpherePackCallback *callback)
|
||||
{
|
||||
bool hit = false;
|
||||
|
||||
if (HasSpherePackFlag(SPF_SUPERSPHERE))
|
||||
{
|
||||
|
||||
hit = RayIntersectionInFront(p1,dir,0);
|
||||
|
||||
if (hit)
|
||||
{
|
||||
#if DEMO
|
||||
DrawCircle(int(mCenter.x), int(mCenter.y), int(GetRadius()), 0x404040);
|
||||
#endif
|
||||
SpherePack *pack = mChildren;
|
||||
|
||||
while (pack)
|
||||
{
|
||||
pack->RayTrace(p1,dir,distance,callback);
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3d sect;
|
||||
hit = RayIntersection(p1,dir,distance,§);
|
||||
if (hit)
|
||||
{
|
||||
callback->RayTraceCallback(p1,dir,distance,sect,this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::RayTraceCallback(const Vector3d &p1, // source pos of ray
|
||||
const Vector3d &dir, // direction of ray
|
||||
float distance, // distance of ray
|
||||
const Vector3d &/*sect*/, // intersection location
|
||||
SpherePack *sphere)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!sphere->IS_SPHERE)
|
||||
puts("SpherePackFactory::RayTraceCallback");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) sphere->GetUserData();
|
||||
if (link) link->RayTrace(p1,dir,distance,mCallback);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void SpherePackFactory::Reset(void)
|
||||
{
|
||||
mRoot->Reset();
|
||||
mLeaf->Reset();
|
||||
}
|
||||
|
||||
|
||||
void SpherePack::Reset(void)
|
||||
{
|
||||
ClearSpherePackFlag(SpherePackFlag(SPF_HIDDEN | SPF_PARTIAL | SPF_INSIDE));
|
||||
|
||||
SpherePack *pack = mChildren;
|
||||
while (pack)
|
||||
{
|
||||
pack->Reset();
|
||||
pack = pack->_GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
void SpherePackFactory::VisibilityCallback(const Frustum &f,SpherePack *sphere,ViewState state)
|
||||
{
|
||||
#ifdef SPHERELIB_STRICT
|
||||
if (!sphere->IS_SPHERE)
|
||||
puts("SpherePackFactory::VisibilityCallback");
|
||||
#endif
|
||||
SpherePack *link = (SpherePack *) sphere->GetUserData();
|
||||
if (link) link->VisibilityTest(f,mCallback,state);
|
||||
}
|
||||
@@ -2775,6 +2775,9 @@ void CInstanceBase::ChangeWeapon(DWORD eWeapon)
|
||||
|
||||
if (SetWeapon(eWeapon))
|
||||
RefreshState(CRaceMotionData::NAME_WAIT, true);
|
||||
|
||||
if (IsAffect(AFFECT_GEOMGYEONG))
|
||||
__Warrior_SetGeomgyeongAffect(true);
|
||||
}
|
||||
|
||||
bool CInstanceBase::ChangeArmor(DWORD dwArmor)
|
||||
@@ -3028,6 +3031,7 @@ void CInstanceBase::__Warrior_Initialize()
|
||||
void CInstanceBase::__Initialize()
|
||||
{
|
||||
__Warrior_Initialize();
|
||||
memset(m_byAffectGrade, 0, sizeof(m_byAffectGrade));
|
||||
__StoneSmoke_Inialize();
|
||||
__EffectContainer_Initialize();
|
||||
__InitializeRotationSpeed();
|
||||
|
||||
@@ -436,6 +436,7 @@ class CInstanceBase
|
||||
|
||||
// 스크립트용 테스트 함수. 나중에 없에자
|
||||
void SCRIPT_SetAffect(UINT eAffect, bool isVisible);
|
||||
void __Warrior_SetGeomgyeongAffect(bool isVisible);
|
||||
|
||||
float CalculateDistanceSq3d(const TPixelPosition& c_rkPPosDst);
|
||||
|
||||
@@ -803,7 +804,7 @@ class CInstanceBase
|
||||
void __ClearMainInstance();
|
||||
|
||||
void __Shaman_SetParalysis(bool isParalysis);
|
||||
void __Warrior_SetGeomgyeongAffect(bool isVisible);
|
||||
BYTE __GetAffectGrade(UINT eAffect);
|
||||
void __Assassin_SetEunhyeongAffect(bool isVisible);
|
||||
void __SetReviveInvisibilityAffect(bool isVisible);
|
||||
|
||||
@@ -1045,6 +1046,7 @@ class CInstanceBase
|
||||
};
|
||||
|
||||
SWarrior m_kWarrior;
|
||||
BYTE m_byAffectGrade[AFFECT_NUM];
|
||||
|
||||
void __Warrior_Initialize();
|
||||
|
||||
|
||||
@@ -340,6 +340,66 @@ bool CInstanceBase::NEW_UseSkill(UINT uSkill, UINT uMot, UINT uMotLoopCount, boo
|
||||
|
||||
m_GraphicThingInstance.__OnUseSkill(uMot, uMotLoopCount, isMovingSkill);
|
||||
|
||||
BYTE bGrade = (uMot >= 25) ? (uMot / 25) : 0;
|
||||
if (bGrade > 3)
|
||||
bGrade = 3;
|
||||
|
||||
if (uSkill != 0)
|
||||
{
|
||||
switch (uSkill)
|
||||
{
|
||||
case 3: m_byAffectGrade[AFFECT_JEONGWI] = bGrade; break;
|
||||
case 4: m_byAffectGrade[AFFECT_GEOMGYEONG] = bGrade; break;
|
||||
case 19: m_byAffectGrade[AFFECT_CHEONGEUN] = bGrade; break;
|
||||
case 34: m_byAffectGrade[AFFECT_EUNHYEONG] = bGrade; break;
|
||||
case 49: m_byAffectGrade[AFFECT_GYEONGGONG] = bGrade; break;
|
||||
case 63: m_byAffectGrade[AFFECT_GWIGEOM] = bGrade; break;
|
||||
case 64: m_byAffectGrade[AFFECT_GONGPO] = bGrade; break;
|
||||
case 65: m_byAffectGrade[AFFECT_JUMAGAP] = bGrade; break;
|
||||
case 78: m_byAffectGrade[AFFECT_MUYEONG] = bGrade; break;
|
||||
case 79: m_byAffectGrade[AFFECT_HEUKSIN] = bGrade; break;
|
||||
case 94: m_byAffectGrade[AFFECT_HOSIN] = bGrade; break;
|
||||
case 95: m_byAffectGrade[AFFECT_BOHO] = bGrade; break;
|
||||
case 96: m_byAffectGrade[AFFECT_GICHEON] = bGrade; break;
|
||||
case 110: m_byAffectGrade[AFFECT_KWAESOK] = bGrade; break;
|
||||
case 111: m_byAffectGrade[AFFECT_JEUNGRYEOK] = bGrade; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT uMotSub = uMot % 25;
|
||||
int iJob = RaceToJob(GetRace());
|
||||
switch (iJob)
|
||||
{
|
||||
case NRaceData::JOB_WARRIOR:
|
||||
if (uMotSub == 3) m_byAffectGrade[AFFECT_JEONGWI] = bGrade;
|
||||
else if (uMotSub == 4) m_byAffectGrade[AFFECT_GEOMGYEONG] = bGrade;
|
||||
else if (uMotSub == 19) m_byAffectGrade[AFFECT_CHEONGEUN] = bGrade;
|
||||
break;
|
||||
case NRaceData::JOB_ASSASSIN:
|
||||
if (uMotSub == 4) m_byAffectGrade[AFFECT_EUNHYEONG] = bGrade;
|
||||
else if (uMotSub == 19) m_byAffectGrade[AFFECT_GYEONGGONG] = bGrade;
|
||||
break;
|
||||
case NRaceData::JOB_SURA:
|
||||
if (uMotSub == 3) m_byAffectGrade[AFFECT_GWIGEOM] = bGrade;
|
||||
else if (uMotSub == 4) m_byAffectGrade[AFFECT_GONGPO] = bGrade;
|
||||
else if (uMotSub == 5) m_byAffectGrade[AFFECT_JUMAGAP] = bGrade;
|
||||
else if (uMotSub == 18) m_byAffectGrade[AFFECT_MUYEONG] = bGrade;
|
||||
else if (uMotSub == 19) m_byAffectGrade[AFFECT_HEUKSIN] = bGrade;
|
||||
break;
|
||||
case NRaceData::JOB_SHAMAN:
|
||||
if (uMotSub == 4) m_byAffectGrade[AFFECT_HOSIN] = bGrade;
|
||||
else if (uMotSub == 5) m_byAffectGrade[AFFECT_BOHO] = bGrade;
|
||||
else if (uMotSub == 6) m_byAffectGrade[AFFECT_GICHEON] = bGrade;
|
||||
else if (uMotSub == 20) m_byAffectGrade[AFFECT_KWAESOK] = bGrade;
|
||||
else if (uMotSub == 21) m_byAffectGrade[AFFECT_JEUNGRYEOK] = bGrade;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsAffect(AFFECT_GEOMGYEONG))
|
||||
__Warrior_SetGeomgyeongAffect(true);
|
||||
|
||||
if (uMotLoopCount > 0)
|
||||
m_GraphicThingInstance.SetMotionLoopCount(uMotLoopCount);
|
||||
|
||||
|
||||
@@ -825,6 +825,29 @@ void CInstanceBase::__Shaman_SetParalysis(bool isParalysis)
|
||||
|
||||
|
||||
|
||||
BYTE CInstanceBase::__GetAffectGrade(UINT eAffect)
|
||||
{
|
||||
if (__IsMainInstance())
|
||||
{
|
||||
DWORD dwSkillIndex = 0;
|
||||
if (CPythonPlayer::Instance().AffectIndexToSkillIndex(eAffect, &dwSkillIndex))
|
||||
{
|
||||
DWORD dwSkillSlotIndex = 0;
|
||||
if (CPythonPlayer::Instance().GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
|
||||
{
|
||||
int iGrade = CPythonPlayer::Instance().GetSkillGrade(dwSkillSlotIndex);
|
||||
if (iGrade >= 0 && iGrade < 4)
|
||||
return (BYTE)iGrade;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eAffect < AFFECT_NUM)
|
||||
return m_byAffectGrade[eAffect];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CInstanceBase::__Warrior_SetGeomgyeongAffect(bool isVisible)
|
||||
{
|
||||
if (isVisible)
|
||||
@@ -836,10 +859,38 @@ void CInstanceBase::__Warrior_SetGeomgyeongAffect(bool isVisible)
|
||||
__DetachEffect(m_kWarrior.m_dwGeomgyeongEffect);
|
||||
|
||||
m_GraphicThingInstance.SetReachScale(1.5f);
|
||||
if (m_GraphicThingInstance.IsTwoHandMode())
|
||||
m_kWarrior.m_dwGeomgyeongEffect=__AttachEffect(EFFECT_WEAPON+WEAPON_TWOHAND);
|
||||
|
||||
BYTE bGrade = __GetAffectGrade(AFFECT_GEOMGYEONG);
|
||||
if (bGrade >= 4)
|
||||
bGrade = 3;
|
||||
|
||||
static const char * c_szGeomSpearFiles[4] = {
|
||||
"d:/ymir work/pc/warrior/effect/geom_spear_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_2_spear_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_3_spear_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_4_spear_loop.mse"
|
||||
};
|
||||
static const char * c_szGeomSwordFiles[4] = {
|
||||
"d:/ymir work/pc/warrior/effect/geom_sword_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_2_sword_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_3_sword_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/geom_4_sword_loop.mse"
|
||||
};
|
||||
|
||||
const char * c_szFileName = m_GraphicThingInstance.IsTwoHandMode() ? c_szGeomSpearFiles[bGrade] : c_szGeomSwordFiles[bGrade];
|
||||
|
||||
DWORD dwEffectCRC = 0;
|
||||
if (CEffectManager::Instance().RegisterEffect2(c_szFileName, &dwEffectCRC, true))
|
||||
{
|
||||
m_kWarrior.m_dwGeomgyeongEffect = m_GraphicThingInstance.AttachEffectByID(0, "equip_right_hand", dwEffectCRC);
|
||||
}
|
||||
else
|
||||
m_kWarrior.m_dwGeomgyeongEffect=__AttachEffect(EFFECT_WEAPON+WEAPON_ONEHAND);
|
||||
{
|
||||
if (m_GraphicThingInstance.IsTwoHandMode())
|
||||
m_kWarrior.m_dwGeomgyeongEffect = __AttachEffect(EFFECT_WEAPON + WEAPON_TWOHAND);
|
||||
else
|
||||
m_kWarrior.m_dwGeomgyeongEffect = __AttachEffect(EFFECT_WEAPON + WEAPON_ONEHAND);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1033,6 +1084,129 @@ DWORD CInstanceBase::__AttachEffect(UINT eEftType)
|
||||
if (eEftType>=EFFECT_NUM)
|
||||
return 0;
|
||||
|
||||
if (eEftType >= EFFECT_AFFECT && eEftType < EFFECT_AFFECT_END)
|
||||
{
|
||||
UINT eAffect = eEftType - EFFECT_AFFECT;
|
||||
BYTE bGrade = __GetAffectGrade(eAffect);
|
||||
if (bGrade >= 4)
|
||||
bGrade = 3;
|
||||
|
||||
const char * c_szFileName = NULL;
|
||||
const char * c_szBoneName = NULL;
|
||||
|
||||
switch (eAffect)
|
||||
{
|
||||
case AFFECT_GWIGEOM:
|
||||
{
|
||||
static const char * c_szGwigeomFiles[4] = {
|
||||
"d:/ymir work/pc/sura/effect/gwigeom_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/gwigeom_2_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/gwigeom_3_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/gwigeom_4_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szGwigeomFiles[bGrade];
|
||||
c_szBoneName = "Bip01 R Finger2";
|
||||
break;
|
||||
}
|
||||
case AFFECT_GONGPO:
|
||||
{
|
||||
static const char * c_szFearFiles[4] = {
|
||||
"d:/ymir work/pc/sura/effect/fear_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/fear_2_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/fear_3_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/fear_3_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szFearFiles[bGrade];
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_JUMAGAP:
|
||||
{
|
||||
static const char * c_szJumagapFiles[4] = {
|
||||
"d:/ymir work/pc/sura/effect/jumagap_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/jumagap_2_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/jumagap_3_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/jumagap_4_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szJumagapFiles[bGrade];
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_HEUKSIN:
|
||||
{
|
||||
static const char * c_szHeuksinFiles[4] = {
|
||||
"d:/ymir work/pc/sura/effect/heuksin_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/heuksin_2_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/heuksin_3_loop.mse",
|
||||
"d:/ymir work/pc/sura/effect/heuksin_4_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szHeuksinFiles[bGrade];
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_HOSIN:
|
||||
{
|
||||
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/3hosin_loop_4.mse" : "d:/ymir work/pc/shaman/effect/3hosin_loop.mse";
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_BOHO:
|
||||
{
|
||||
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/boho_loop_4.mse" : "d:/ymir work/pc/shaman/effect/boho_loop.mse";
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_GYEONGGONG:
|
||||
{
|
||||
static const char * c_szGyeonggongFiles[4] = {
|
||||
"d:/ymir work/pc/assassin/effect/gyeonggong_loop.mse",
|
||||
"d:/ymir work/pc/assassin/effect/gyeonggong_2_loop.mse",
|
||||
"d:/ymir work/pc/assassin/effect/gyeonggong_3_loop.mse",
|
||||
"d:/ymir work/pc/assassin/effect/gyeonggong_4_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szGyeonggongFiles[bGrade];
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_CHEONGEUN:
|
||||
{
|
||||
static const char * c_szCheongeunFiles[4] = {
|
||||
"d:/ymir work/pc/warrior/effect/gyeokgongjang_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/gyeokgongjang_2_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/gyeokgongjang_3_loop.mse",
|
||||
"d:/ymir work/pc/warrior/effect/gyeokgongjang_3_loop.mse"
|
||||
};
|
||||
c_szFileName = c_szCheongeunFiles[bGrade];
|
||||
c_szBoneName = "";
|
||||
break;
|
||||
}
|
||||
case AFFECT_GICHEON:
|
||||
{
|
||||
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/6gicheon_hand_4.mse" : "d:/ymir work/pc/shaman/effect/6gicheon_hand.mse";
|
||||
c_szBoneName = "Bip01 R Hand";
|
||||
break;
|
||||
}
|
||||
case AFFECT_JEUNGRYEOK:
|
||||
{
|
||||
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/jeungryeok_hand_4.mse" : "d:/ymir work/pc/shaman/effect/jeungryeok_hand.mse";
|
||||
c_szBoneName = "Bip01 L Hand";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (c_szFileName)
|
||||
{
|
||||
DWORD dwEffectCRC = 0;
|
||||
if (CEffectManager::Instance().RegisterEffect2(c_szFileName, &dwEffectCRC, true))
|
||||
{
|
||||
const char * bone = (c_szBoneName && c_szBoneName[0]) ? c_szBoneName : NULL;
|
||||
return m_GraphicThingInstance.AttachEffectByID(0, bone, dwEffectCRC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ms_astAffectEffectAttachBone[eEftType].empty())
|
||||
{
|
||||
return m_GraphicThingInstance.AttachEffectByID(0, NULL, ms_adwCRCAffectEffect[eEftType]);
|
||||
|
||||
@@ -274,17 +274,7 @@ class CPythonApplication final : public CMSApplication, public CInputKeyboard, p
|
||||
int m_nLeft, m_nRight, m_nTop, m_nBottom;
|
||||
|
||||
|
||||
protected:
|
||||
LRESULT WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void OnCameraUpdate();
|
||||
|
||||
void OnUIUpdate();
|
||||
void OnUIRender();
|
||||
|
||||
void OnMouseUpdate();
|
||||
void OnMouseRender();
|
||||
|
||||
public:
|
||||
void OnMouseWheel(int nLen);
|
||||
void OnMouseMove(int x, int y);
|
||||
void OnMouseMiddleButtonDown(int x, int y);
|
||||
@@ -299,6 +289,17 @@ class CPythonApplication final : public CMSApplication, public CInputKeyboard, p
|
||||
void OnKeyUp(int iIndex);
|
||||
void OnIMEKeyDown(int iIndex);
|
||||
|
||||
protected:
|
||||
LRESULT WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void OnCameraUpdate();
|
||||
|
||||
void OnUIUpdate();
|
||||
void OnUIRender();
|
||||
|
||||
void OnMouseUpdate();
|
||||
void OnMouseRender();
|
||||
|
||||
int CheckDeviceState();
|
||||
|
||||
BOOL __IsContinuousChangeTypeCursor(int iCursorNum);
|
||||
|
||||
@@ -254,10 +254,34 @@ void CPythonBackground::__CreateProperty()
|
||||
{
|
||||
// The exported client runs with player settings as CWD; its read-only property pack
|
||||
// lives beside the other bundled 40250 packs. Use the same root registered by PackBackend.
|
||||
std::string property_pack = "pack/property";
|
||||
std::vector<std::string> candidates;
|
||||
if (const char* client = getenv("MT_40250_CLIENT"))
|
||||
property_pack = std::string(client) + "/pack/Property";
|
||||
m_PropertyManager.Initialize(property_pack.c_str());
|
||||
{
|
||||
candidates.push_back(std::string(client) + "/pack/Property");
|
||||
candidates.push_back(std::string(client) + "/pack/property");
|
||||
}
|
||||
candidates.push_back("pack/Property");
|
||||
candidates.push_back("pack/property");
|
||||
candidates.push_back("Client/pack/Property");
|
||||
candidates.push_back("Client/pack/property");
|
||||
|
||||
bool initialized = false;
|
||||
for (const auto& path : candidates)
|
||||
{
|
||||
std::string eix = path + ".eix";
|
||||
if (_access(eix.c_str(), 0) == 0)
|
||||
{
|
||||
if (m_PropertyManager.Initialize(path.c_str()))
|
||||
{
|
||||
initialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!initialized && !candidates.empty())
|
||||
{
|
||||
m_PropertyManager.Initialize(candidates.front().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -735,6 +735,11 @@ void CPythonCharacterManager::__SortPickedActorList()
|
||||
std::sort(m_kVct_pkInstPicked.begin(), m_kVct_pkInstPicked.end(), kLess);
|
||||
}
|
||||
|
||||
void CPythonCharacterManager::Pick()
|
||||
{
|
||||
__NEW_Pick();
|
||||
}
|
||||
|
||||
void CPythonCharacterManager::__NEW_Pick()
|
||||
{
|
||||
__UpdateSortPickedActorList();
|
||||
@@ -773,31 +778,10 @@ void CPythonCharacterManager::__NEW_Pick()
|
||||
}
|
||||
}
|
||||
|
||||
// 못찾겠으면 걍 순서대로
|
||||
{
|
||||
std::vector<CInstanceBase*>::iterator f;
|
||||
for (f=m_kVct_pkInstPicked.begin(); f!=m_kVct_pkInstPicked.end(); ++f)
|
||||
{
|
||||
CInstanceBase* pkInstEach=*f;
|
||||
if (pkInstEach!=pkInstMain)
|
||||
{
|
||||
if (m_pkInstPick)
|
||||
if (m_pkInstPick!=pkInstEach)
|
||||
m_pkInstPick->OnUnselected();
|
||||
|
||||
if (pkInstEach->CanPickInstance())
|
||||
{
|
||||
m_pkInstPick = pkInstEach;
|
||||
m_pkInstPick->OnSelected();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pkInstMain)
|
||||
if (pkInstMain->CanPickInstance())
|
||||
if (m_kVct_pkInstPicked.end() != std::find(m_kVct_pkInstPicked.begin(), m_kVct_pkInstPicked.end(), pkInstMain))
|
||||
if (pkInstMain->IntersectBoundingBox())
|
||||
{
|
||||
if (m_pkInstPick)
|
||||
if (m_pkInstPick!=pkInstMain)
|
||||
|
||||
@@ -85,6 +85,7 @@ class CPythonCharacterManager : public CSingleton<CPythonCharacterManager>, publ
|
||||
CInstanceBase * GetInstancePtrByName(const char *name);
|
||||
|
||||
// Pick
|
||||
void Pick();
|
||||
int PickAll();
|
||||
CInstanceBase * GetCloseInstance(CInstanceBase * pInstance);
|
||||
|
||||
|
||||
@@ -1037,6 +1037,25 @@ void CPythonPlayer::SetSkillLevel_(DWORD dwSkillIndex, DWORD dwSkillGrade, DWORD
|
||||
m_playerStatus.aSkill[dwSlotIndex].fcurEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel)/100.0f;
|
||||
m_playerStatus.aSkill[dwSlotIndex].fnextEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel+1)/100.0f;
|
||||
|
||||
CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
|
||||
if (pkInstMain)
|
||||
{
|
||||
if (dwSkillIndex == 4 && pkInstMain->IsAffect(CInstanceBase::AFFECT_GEOMGYEONG))
|
||||
{
|
||||
pkInstMain->__Warrior_SetGeomgyeongAffect(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::map<DWORD, DWORD>::const_iterator it = m_kMap_dwAffectIndexToSkillIndex.begin(); it != m_kMap_dwAffectIndexToSkillIndex.end(); ++it)
|
||||
{
|
||||
if (it->second == dwSkillIndex && pkInstMain->IsAffect(it->first))
|
||||
{
|
||||
pkInstMain->SCRIPT_SetAffect(it->first, false);
|
||||
pkInstMain->SCRIPT_SetAffect(it->first, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::SetSkillCoolTime(DWORD dwSkillIndex)
|
||||
|
||||
@@ -12,7 +12,7 @@ std::map<std::string, DWORD> CPythonSkill::SSkillData::ms_NewMinStatusNameMap;
|
||||
std::map<std::string, DWORD> CPythonSkill::SSkillData::ms_NewMaxStatusNameMap;
|
||||
DWORD CPythonSkill::SSkillData::ms_dwTimeIncreaseSkillNumber = 0;
|
||||
|
||||
BOOL SKILL_EFFECT_UPGRADE_ENABLE = FALSE;
|
||||
BOOL SKILL_EFFECT_UPGRADE_ENABLE = TRUE;
|
||||
|
||||
int SplitLine(const char * c_szText, CTokenVector* pstTokenVector, const char * c_szDelimeter)
|
||||
{
|
||||
|
||||
@@ -757,6 +757,7 @@ struct IDirect3DDevice8
|
||||
virtual ULONG Release() = 0;
|
||||
virtual HRESULT GetDeviceCaps(D3DCAPS8* pCaps) = 0;
|
||||
virtual HRESULT GetViewport(D3DVIEWPORT8* pViewport) = 0;
|
||||
virtual HRESULT SetViewport(const D3DVIEWPORT8* pViewport) = 0;
|
||||
virtual UINT GetAvailableTextureMem() = 0;
|
||||
virtual HRESULT BeginScene() = 0;
|
||||
virtual HRESULT EndScene() = 0;
|
||||
|
||||
Reference in New Issue
Block a user