Files
Client/GameTools/Zallad3D SceneClass/ROcclusion.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

405 lines
10 KiB
C++

#include "ROcclusion.h"
/*
void ROcclusion::CheckCulling(LPDIRECT3DDEVICE8 ,ROcclusionUnit *list,int num,float camera_x,float camera_y,float camera_z);
void ROcclusion::SortList(ROcclusionUnit *,int num,float camerax,float cameray,float cameraz,LPDIRECT3DDEVICE8 );
void ROcclusion::HorizonCull(LPDIRECT3DDEVICE8 ,ROcclusionUnit *,int listnum);
void ROcclusion::Hculling(ROcclusionUnit *list,int listnum,int start_index,float ,float ,float );
void ROcclusion::InitVolume();
*/
ROcclusionVolume *ROcclusion::m_Volume;
unsigned long ROcclusion::m_VWidth;
unsigned long ROcclusion::m_VHeight;
int ROcclusion::m_ViewObject;
int ROcclusion::m_HidenObject;
/////////////////////////////// ROcclusionUnit ////////////////////////////////////
void ROcclusionUnit::FindPoint(D3DXVECTOR3 *point)
{
int i;
D3DXVECTOR3 tmp_sum = D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 tmp_cube[8];
int min_index = 0;
int max_index = 0;
int zover_count = 0;
int zover_count2 = 0;
unsigned long Screen_width = 0;
unsigned long Screen_height = 0;
D3DXMATRIX t_project;
D3DXMATRIX t_view;
D3DXMATRIX t_world;
D3DXVECTOR3 view_vec[3];
D3DXVECTOR4 view_vec2[3];
D3DVIEWPORT8 t_viewport;
D3DXVECTOR3 min_value,max_value,target_value;
m_Device->GetTransform(D3DTS_VIEW,&t_view);
m_Device->GetViewport(&t_viewport);
m_Device->GetTransform(D3DTS_WORLD,&t_world);
m_Device->GetTransform(D3DTS_PROJECTION,&t_project);
Screen_width = t_viewport.Width;
Screen_height = t_viewport.Height;
for( i=0; i < 8; i++ )
{
tmp_cube[i] = D3DXVECTOR3(m_Cube.m_vecVertex[i].x,m_Cube.m_vecVertex[i].y,m_Cube.m_vecVertex[i].z);
tmp_sum += tmp_cube[i];
D3DXVec3Project(&(view_vec[0]),
&(tmp_cube[min_index]),
&t_viewport,
&t_project,
&t_view,
&t_world);
D3DXVec3Project(&(view_vec[1]),
&(tmp_cube[i]),
&t_viewport,
&t_project,
&t_view,
&t_world);
D3DXVec3Project(&(view_vec[2]),
&(tmp_cube[max_index]),
&t_viewport,
&t_project,
&t_view,
&t_world);
max_value = view_vec[2];
min_value = view_vec[0];
target_value = view_vec[1];
//z value가 0 ~ 1을 넘어가면 화면 영역을 넘은것이다
if( target_value.z > 1.0f || target_value.z < 0.0f )
{
zover_count++;
zover_count2++;
continue;
}
if( min_value.z > 1.0f || min_value.z <0.0f )
{
min_index = i;
zover_count++;
}
if( max_value.z > 1.0f || max_value.z <0.0f )
{
max_index = i;
zover_count2++;
}
if( min_value.x > target_value.x ) { //min value
min_index = i;
}
else if( min_value.x == target_value.x )
{
if( min_value.y > target_value.y )
min_index = i;
}
if( max_value.x == target_value.x ) //max value
{
if( max_value.y > target_value.y )
max_index = i;
}
else if( max_value.x < target_value.x )
{
max_index = i;
}
}//for
tmp_sum /=8;
point[2] = tmp_sum;
if(zover_count >= 8) // min value overflow
point[0] = D3DXVECTOR3(FAIL,FAIL,FAIL);
else
point[0] = tmp_cube[min_index];
if(zover_count2 >= 8) // max value overflow
point[1] = D3DXVECTOR3(FAIL,FAIL,FAIL);
else
point[1] = tmp_cube[max_index];
}
void ROcclusionUnit::Create(LPDIRECT3DDEVICE8 device)
{
m_Device = device;
D3DXVECTOR3 Point[3];
D3DXVECTOR3 min;
D3DXVECTOR3 max;
D3DXVECTOR3 center;
FindPoint(Point);
min = Point[0];
max = Point[1];
center = Point[2];
// 점들이 모두 화면 바깥에 있을때
if( min.x == FAIL && min.y == FAIL && min.z == FAIL )
(*m_bVis) = false;
if( max.x == FAIL && max.y == FAIL && max.z == FAIL )
(*m_bVis) = false;
//
CreateOccBox(min,max,center,false);
}
//int projected arg == min,max 점이 이미 프로젝션 되어있는지..
void ROcclusionUnit::CreateOccBox(D3DXVECTOR3 min,D3DXVECTOR3 max,D3DXVECTOR3 center,bool projected)
{
m_OccBox.m_vecCenter = center;
if(!projected) //world axis min max point input
{
// min point,max point setting
D3DXVECTOR3 projectedpoint[2];
D3DXMATRIX t_project;
D3DXMATRIX t_view;
D3DXMATRIX t_world;
D3DVIEWPORT8 t_viewport;
m_Device->GetViewport(&t_viewport);
m_Device->GetTransform(D3DTS_WORLD,&t_world);
m_Device->GetTransform(D3DTS_VIEW,&t_view);
m_Device->GetTransform(D3DTS_PROJECTION,&t_project);
//projected 2d space
D3DXVec3Project(&(projectedpoint[0]),
&(min),
&t_viewport,
&t_project,
&t_view,
&t_world);
D3DXVec3Project(&(projectedpoint[1]),
&(max),
&t_viewport,
&t_project,
&t_view,
&t_world);
m_OccBox.m_vecMin.x = projectedpoint[0].x;
m_OccBox.m_vecMin.y = projectedpoint[0].y;
m_OccBox.m_vecMax.x = projectedpoint[1].x;
m_OccBox.m_vecMax.y = projectedpoint[1].y;
}
else //이미 projection 된 상태로 들어왔을때
{
m_OccBox.m_vecMin.x = min.x;
m_OccBox.m_vecMin.y = min.y;
m_OccBox.m_vecMax.x = max.x;
m_OccBox.m_vecMax.y = max.y;
}
}
////////////////////////////////////////////////////////////////////////////////
int OcclusionHCompare(const void *arg1,const void *arg2)
{
if(((ROcclusionUnit *)arg1)->m_OccBox.m_fZValue > ((ROcclusionUnit *)arg2)->m_OccBox.m_fZValue)
return 1;
else if(((ROcclusionUnit *)arg1)->m_OccBox.m_fZValue < ((ROcclusionUnit *)arg2)->m_OccBox.m_fZValue)
return -1;
return 0;
}
//camera 위치에 가까운 순서로 list sort
void ROcclusion::SortList(ROcclusionUnit *list,int num,float camerax,float cameray,float cameraz,LPDIRECT3DDEVICE8 device)
{
int i;
D3DXMATRIX cameratm;
D3DXMATRIX invcamera;
device->GetTransform(D3DTS_VIEW,&cameratm);
D3DXMatrixInverse(&invcamera,NULL,&cameratm);
D3DXVECTOR4 src,dst;
for( i=0; i < num; i++ )
{
D3DXVec3Transform(&src,&list[i].m_OccBox.m_vecCenter,&cameratm);
list[i].m_OccBox.m_fZValue = src.z;
}
qsort((void *)list,(size_t)num, sizeof(ROcclusionUnit),OcclusionHCompare);
}
void ROcclusion::CheckCulling(LPDIRECT3DDEVICE8 device,ROcclusionUnit *list,int num,float camera_x,float camera_y,float camera_z) {
int i;
for( i = 0; i < num ; i++)
list[i].Create(device); // 2D Box Create
SortList(list,num,camera_x,camera_y,camera_z,device);
HorizonCull(device,list,num);
m_ViewObject = m_HidenObject = 0;
//culling info set
for( i = 0; i < num; i++ )
{
if( (*list[i].m_bVis) )
m_ViewObject++;
else
m_HidenObject++;
}
}
void ROcclusion::InitVolume() // Screen Volume Init
{
for(int k=0;k<(int)m_VWidth;k++)
m_Volume[k].m_Height = (float)m_VHeight;
}
//현재 노드 까지 생성된 볼륨에 기반하여 culling 수행
void ROcclusion::Hculling(ROcclusionUnit *list,int listnum,int start_index,float camerax,float cameray,float cameraz)
{
for( int i = start_index; i < listnum; i++ )
{
if( (*list[i].m_bVis) ) // 검사 현재까지 보이는 객체에만 검사
{
int count = 0;
if( list[i].m_OccBox.m_vecMin.x > list[i].m_OccBox.m_vecMax.x )
{
float tmp_index = list[i].m_OccBox.m_vecMin.x;
list[i].m_OccBox.m_vecMin.x = list[i].m_OccBox.m_vecMax.x;
list[i].m_OccBox.m_vecMax.x = tmp_index;
}
// 높이 맟춤
list[i].m_OccBox.m_vecMin.y = ( list[i].m_OccBox.m_vecMin.y > list[i].m_OccBox.m_vecMax.y ) ? list[i].m_OccBox.m_vecMin.y : list[i].m_OccBox.m_vecMax.y;
list[i].m_OccBox.m_vecMax.y = list[i].m_OccBox.m_vecMin.y;
list[i].m_OccBox.m_vecMin.y = list[i].m_OccBox.m_vecMax.y = ( list[i].m_OccBox.m_vecMin.y > m_VHeight ) ? m_VHeight :
( (list[i].m_OccBox.m_vecMin.y < 0) ? 0 : list[i].m_OccBox.m_vecMin.y);
list[i].m_OccBox.m_vecMin.x = (list[i].m_OccBox.m_vecMin.x < 0 ) ? 0 : ((list[i].m_OccBox.m_vecMin.x > m_VWidth) ? (float)m_VWidth : list[i].m_OccBox.m_vecMin.x);
list[i].m_OccBox.m_vecMax.x = (list[i].m_OccBox.m_vecMax.x < 0 ) ? 0 : ((list[i].m_OccBox.m_vecMax.x > m_VWidth) ? (float)m_VWidth : list[i].m_OccBox.m_vecMax.x);
int min_index = (int)list[i].m_OccBox.m_vecMin.x;
int max_index = (int)list[i].m_OccBox.m_vecMax.x;
int width = max_index - min_index;
for(int k=min_index;k<max_index;k++)
{
if(m_Volume[k].m_Height < list[i].m_OccBox.m_vecMin.y) // not visible
count++;
}
if(count >= width) // 2d box 전부가 가려졌다면
(*list[i].m_bVis) = false;
else
(*list[i].m_bVis) = true;
}
}
}
// 이미 카메라의 거리에 따른 sort 된 뒤므로 순서대로 볼륨 만들면 된다
void ROcclusion::HorizonCull(LPDIRECT3DDEVICE8 device,ROcclusionUnit *list,int listnum)
{
if( m_Volume == NULL ) // 가장처음 Volume을 Create 할때.
{
D3DVIEWPORT8 t_viewport;
device->GetViewport(&t_viewport);
m_VWidth = t_viewport.Width; // Screen 의 좌표를 얻어온다
m_VHeight = t_viewport.Height;
m_Volume = new ROcclusionVolume[m_VWidth];
}
else
{
InitVolume(); // Volume 초기화
}
for(int i=0;i<listnum;i++)
{
// min, max 점 중에 화면을 넘어간 점이 있는지 set
if(list[i].m_OccBox.m_fZValue < 0) {
(*(list[i].m_bVis)) = false;
continue;
}
if( (*list[i].m_bVis) )
{
if( list[i].m_OccBox.m_vecMin.x > list[i].m_OccBox.m_vecMax.x )
{
float tmp_index = list[i].m_OccBox.m_vecMin.x;
list[i].m_OccBox.m_vecMin.x = list[i].m_OccBox.m_vecMax.x;
list[i].m_OccBox.m_vecMax.x = tmp_index;
}
// 높이 맟춤
list[i].m_OccBox.m_vecMin.y = ( list[i].m_OccBox.m_vecMin.y > list[i].m_OccBox.m_vecMax.y ) ? list[i].m_OccBox.m_vecMin.y : list[i].m_OccBox.m_vecMax.y;
list[i].m_OccBox.m_vecMax.y = list[i].m_OccBox.m_vecMin.y;
if(list[i].m_OccBox.m_vecMin.y == 0 && list[i].m_OccBox.m_vecMax.y == 0)
continue;
list[i].m_OccBox.m_vecMin.y = list[i].m_OccBox.m_vecMax.y = ( list[i].m_OccBox.m_vecMin.y > m_VHeight ) ? m_VHeight : ( (list[i].m_OccBox.m_vecMin.y < 0) ? 0 : list[i].m_OccBox.m_vecMin.y );
list[i].m_OccBox.m_vecMin.x = (list[i].m_OccBox.m_vecMin.x < 0 ) ? 0 : ((list[i].m_OccBox.m_vecMin.x > m_VWidth) ? (float)m_VWidth : list[i].m_OccBox.m_vecMin.x);
list[i].m_OccBox.m_vecMax.x = (list[i].m_OccBox.m_vecMax.x < 0 ) ? 0 : ((list[i].m_OccBox.m_vecMax.x > m_VWidth) ? (float)m_VWidth : list[i].m_OccBox.m_vecMax.x);
int min_index = (int)list[i].m_OccBox.m_vecMin.x;
int max_index = (int)list[i].m_OccBox.m_vecMax.x + 1;
//////
int width = max_index - min_index;
for(int j=min_index;j<=max_index;j++)
{
if(m_Volume[j].m_Height >= list[i].m_OccBox.m_vecMin.y)
m_Volume[j].m_Height = list[i].m_OccBox.m_vecMin.y;
}
// culling 적용
D3DXMATRIX view;
D3DXMATRIX inv;
device->GetTransform(D3DTS_VIEW,&view);
D3DXMatrixInverse(&inv,NULL,&view);
Hculling(list,listnum,i+1,inv._41,inv._42,inv._43);
}
}
}