2012-12-08 02:05:23 +00:00
//
// KRCollider.cpp
// KREngine
//
// Copyright 2012 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
2013-01-11 03:21:19 +00:00
# include "KREngine-common.h"
2012-12-08 02:05:23 +00:00
# include "KRCollider.h"
2013-01-11 03:21:19 +00:00
# include "KRContext.h"
# include "KRMesh.h"
# include "KRQuaternion.h"
2012-12-08 02:05:23 +00:00
2013-01-09 22:37:23 +00:00
KRCollider : : KRCollider ( KRScene & scene , std : : string collider_name , std : : string model_name , unsigned int layer_mask , float audio_occlusion ) : KRNode ( scene , collider_name ) {
2012-12-08 02:05:23 +00:00
m_model_name = model_name ;
2013-01-09 22:37:23 +00:00
m_layer_mask = layer_mask ;
m_audio_occlusion = audio_occlusion ;
2012-12-08 02:05:23 +00:00
}
KRCollider : : ~ KRCollider ( ) {
}
std : : string KRCollider : : getElementName ( ) {
return " collider " ;
}
tinyxml2 : : XMLElement * KRCollider : : saveXML ( tinyxml2 : : XMLNode * parent )
{
tinyxml2 : : XMLElement * e = KRNode : : saveXML ( parent ) ;
2013-01-09 22:37:23 +00:00
e - > SetAttribute ( " mesh " , m_model_name . c_str ( ) ) ;
e - > SetAttribute ( " layer_mask " , m_layer_mask ) ;
e - > SetAttribute ( " audio_occlusion " , m_audio_occlusion ) ;
2012-12-08 02:05:23 +00:00
return e ;
}
2013-01-09 22:37:23 +00:00
void KRCollider : : loadXML ( tinyxml2 : : XMLElement * e ) {
KRNode : : loadXML ( e ) ;
m_model_name = e - > Attribute ( " mesh " ) ;
m_layer_mask = 65535 ;
if ( e - > QueryUnsignedAttribute ( " layer_mask " , & m_layer_mask ) ! = tinyxml2 : : XML_SUCCESS ) {
m_layer_mask = 65535 ;
}
m_audio_occlusion = 1.0f ;
if ( e - > QueryFloatAttribute ( " audio_occlusion " , & m_audio_occlusion ) ! = tinyxml2 : : XML_SUCCESS ) {
m_audio_occlusion = 1.0f ;
}
}
2012-12-08 02:05:23 +00:00
void KRCollider : : loadModel ( ) {
if ( m_models . size ( ) = = 0 ) {
m_models = m_pContext - > getModelManager ( ) - > getModel ( m_model_name . c_str ( ) ) ; // The model manager returns the LOD levels in sorted order, with the highest detail first
if ( m_models . size ( ) > 0 ) {
getScene ( ) . notify_sceneGraphModify ( this ) ;
}
}
}
KRAABB KRCollider : : getBounds ( ) {
loadModel ( ) ;
if ( m_models . size ( ) > 0 ) {
return KRAABB ( m_models [ 0 ] - > getMinPoint ( ) , m_models [ 0 ] - > getMaxPoint ( ) , getModelMatrix ( ) ) ;
} else {
return KRAABB : : Infinite ( ) ;
}
}
2013-01-09 22:37:23 +00:00
bool KRCollider : : lineCast ( const KRVector3 & v0 , const KRVector3 & v1 , KRHitInfo & hitinfo , unsigned int layer_mask )
2012-12-15 01:39:32 +00:00
{
2013-01-09 22:37:23 +00:00
if ( layer_mask & m_layer_mask ) { // Only test if layer masks have a common bit set
loadModel ( ) ;
if ( m_models . size ( ) ) {
if ( getBounds ( ) . intersectsLine ( v0 , v1 ) ) {
2013-05-01 15:07:27 -07:00
KRHitInfo hitinfo_model_space ;
if ( hitinfo . didHit ( ) ) {
hitinfo_model_space = KRHitInfo ( KRMat4 : : Dot ( getInverseModelMatrix ( ) , hitinfo . getPosition ( ) ) , KRMat4 : : DotNoTranslate ( getInverseModelMatrix ( ) , hitinfo . getNormal ( ) ) , hitinfo . getNode ( ) ) ;
}
2013-01-09 22:37:23 +00:00
KRVector3 v0_model_space = KRMat4 : : Dot ( getInverseModelMatrix ( ) , v0 ) ;
KRVector3 v1_model_space = KRMat4 : : Dot ( getInverseModelMatrix ( ) , v1 ) ;
if ( m_models [ 0 ] - > lineCast ( v0_model_space , v1_model_space , hitinfo_model_space ) ) {
hitinfo = KRHitInfo ( KRMat4 : : Dot ( getModelMatrix ( ) , hitinfo_model_space . getPosition ( ) ) , KRVector3 : : Normalize ( KRMat4 : : DotNoTranslate ( getModelMatrix ( ) , hitinfo_model_space . getNormal ( ) ) ) , this ) ;
return true ;
}
2012-12-20 01:23:57 +00:00
}
2012-12-15 01:39:32 +00:00
}
}
return false ;
}
2013-01-09 22:37:23 +00:00
bool KRCollider : : rayCast ( const KRVector3 & v0 , const KRVector3 & dir , KRHitInfo & hitinfo , unsigned int layer_mask )
2012-12-15 01:39:32 +00:00
{
2013-01-09 22:37:23 +00:00
if ( layer_mask & m_layer_mask ) { // Only test if layer masks have a common bit set
loadModel ( ) ;
if ( m_models . size ( ) ) {
if ( getBounds ( ) . intersectsRay ( v0 , dir ) ) {
2013-05-01 15:07:27 -07:00
KRHitInfo hitinfo_model_space ;
if ( hitinfo . didHit ( ) ) {
hitinfo_model_space = KRHitInfo ( KRMat4 : : Dot ( getInverseModelMatrix ( ) , hitinfo . getPosition ( ) ) , KRVector3 : : Normalize ( KRMat4 : : DotNoTranslate ( getInverseModelMatrix ( ) , hitinfo . getNormal ( ) ) ) , hitinfo . getNode ( ) ) ;
}
2013-01-09 22:37:23 +00:00
KRVector3 v0_model_space = KRMat4 : : Dot ( getInverseModelMatrix ( ) , v0 ) ;
2013-05-01 15:07:27 -07:00
KRVector3 dir_model_space = KRVector3 : : Normalize ( KRMat4 : : DotNoTranslate ( getInverseModelMatrix ( ) , dir ) ) ;
if ( m_models [ 0 ] - > rayCast ( v0_model_space , dir_model_space , hitinfo_model_space ) ) {
2013-01-09 22:37:23 +00:00
hitinfo = KRHitInfo ( KRMat4 : : Dot ( getModelMatrix ( ) , hitinfo_model_space . getPosition ( ) ) , KRVector3 : : Normalize ( KRMat4 : : DotNoTranslate ( getModelMatrix ( ) , hitinfo_model_space . getNormal ( ) ) ) , this ) ;
return true ;
}
2012-12-20 01:23:57 +00:00
}
2012-12-15 01:39:32 +00:00
}
}
return false ;
}
2013-01-09 22:37:23 +00:00
unsigned int KRCollider : : getLayerMask ( )
{
return m_layer_mask ;
}
void KRCollider : : setLayerMask ( unsigned int layer_mask )
{
m_layer_mask = layer_mask ;
}
float KRCollider : : getAudioOcclusion ( )
{
return m_audio_occlusion ;
}
void KRCollider : : setAudioOcclusion ( float audio_occlusion )
{
m_audio_occlusion = audio_occlusion ;
}
2013-05-01 12:32:16 -07:00
void KRCollider : : render ( KRCamera * pCamera , std : : vector < KRPointLight * > & point_lights , std : : vector < KRDirectionalLight * > & directional_lights , std : : vector < KRSpotLight * > & spot_lights , const KRViewport & viewport , KRNode : : RenderPass renderPass )
{
KRNode : : render ( pCamera , point_lights , directional_lights , spot_lights , viewport , renderPass ) ;
if ( renderPass = = KRNode : : RENDER_PASS_FORWARD_TRANSPARENT & & pCamera - > settings . debug_display = = KRRenderSettings : : KRENGINE_DEBUG_DISPLAY_COLLIDERS ) {
loadModel ( ) ;
if ( m_models . size ( ) ) {
GL_PUSH_GROUP_MARKER ( " Debug Overlays " ) ;
KRShader * pShader = getContext ( ) . getShaderManager ( ) - > getShader ( " visualize_overlay " , pCamera , point_lights , directional_lights , spot_lights , 0 , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , false , renderPass ) ;
if ( getContext ( ) . getShaderManager ( ) - > selectShader ( * pCamera , pShader , viewport , getModelMatrix ( ) , point_lights , directional_lights , spot_lights , 0 , renderPass ) ) {
// Enable additive blending
GLDEBUG ( glEnable ( GL_BLEND ) ) ;
GLDEBUG ( glBlendFunc ( GL_ONE , GL_ONE ) ) ;
// Disable z-buffer write
GLDEBUG ( glDepthMask ( GL_FALSE ) ) ;
// Enable z-buffer test
GLDEBUG ( glEnable ( GL_DEPTH_TEST ) ) ;
GLDEBUG ( glDepthFunc ( GL_LEQUAL ) ) ;
GLDEBUG ( glDepthRangef ( 0.0 , 1.0 ) ) ;
for ( int i = 0 ; i < m_models [ 0 ] - > getSubmeshCount ( ) ; i + + ) {
m_models [ 0 ] - > renderSubmesh ( i , renderPass , getName ( ) , " visualize_overlay " ) ;
}
// Enable alpha blending
GLDEBUG ( glEnable ( GL_BLEND ) ) ;
2013-05-02 13:32:36 -07:00
GLDEBUG ( glBlendFunc ( GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ) ;
2013-05-01 12:32:16 -07:00
}
GL_POP_GROUP_MARKER ;
}
}
}