Updated Subrepos, hydra data types are now POD -- refactored Kraken to match. Eliminated some warnings

This commit is contained in:
2018-07-27 00:18:30 -07:00
parent d31a9b0538
commit 96412e1530
60 changed files with 12557 additions and 16027 deletions

12
.gitignore vendored
View File

@@ -1,4 +1,8 @@
.vs/
Kraken.xcodeproj/xcuserdata
kraken_win/build/
build/
.vs/
Kraken.xcodeproj/xcuserdata
kraken_win/build/
build/
kraken.dir/
Win32/
x64/
kraken_win

2
3rdparty/glad vendored

2
3rdparty/glfw vendored

2
hydra

Submodule hydra updated: 00bb9b6689...759b7af066

View File

@@ -1,91 +1,81 @@
include_directories(public)
add_subdirectory(public)
set(KRAKEN_PUBLIC_HEADERS "${KRAKEN_PUBLIC_HEADERS}" PARENT_SCOPE)
add_sources(scalar.cpp)
add_sources(vector2.cpp)
add_sources(vector3.cpp)
add_sources(vector4.cpp)
add_sources(triangle3.cpp)
add_sources(quaternion.cpp)
add_sources(matrix4.cpp)
add_sources(aabb.cpp)
add_sources(hitinfo.cpp)
# Private Implementation
add_sources(KRAmbientZone.cpp)
add_sources(KRAnimation.cpp)
add_sources(KRAnimationAttribute.cpp)
add_sources(KRAnimationCurve.cpp)
add_sources(KRAnimationCurveManager.cpp)
add_sources(KRAnimationLayer.cpp)
add_sources(KRAnimationManager.cpp)
add_sources(KRAudioBuffer.cpp)
add_sources(KRAudioManager.cpp)
add_sources(KRAudioSample.cpp)
add_sources(KRAudioSource.cpp)
add_sources(KRBehavior.cpp)
add_sources(KRBone.cpp)
add_sources(KRBundle.cpp)
add_sources(KRBundleManager.cpp)
add_sources(KRCamera.cpp)
add_sources(KRCollider.cpp)
add_sources(KRContext.cpp)
IF(APPLE)
add_sources(KREngine.mm)
add_sources(KRStreamer.mm)
IF(IOS)
add_sources(KRContext_ios.mm)
ELSE()
add_sources(KRContext_osx.mm)
ENDIF()
ENDIF (APPLE)
add_sources(KRContextObject.cpp)
add_sources(KRDataBlock.cpp)
add_sources(KRDirectionalLight.cpp)
IF(APPLE)
add_sources(KRDSP_vDSP.cpp)
ELSE()
add_sources(KRDSP_slow.cpp)
ENDIF()
add_sources(KRHelpers.cpp)
add_sources(KRLight.cpp)
add_sources(KRLocator.cpp)
add_sources(KRLODGroup.cpp)
add_sources(KRLODSet.cpp)
add_sources(KRMaterial.cpp)
add_sources(KRMaterialManager.cpp)
add_sources(KRMesh.cpp)
add_sources(KRMeshCube.cpp)
add_sources(KRMeshManager.cpp)
add_sources(KRMeshQuad.cpp)
add_sources(KRMeshSphere.cpp)
add_sources(KRModel.cpp)
add_sources(KRNode.cpp)
add_sources(KROctree.cpp)
add_sources(KROctreeNode.cpp)
add_sources(KRParticleSystem.cpp)
add_sources(KRParticleSystemNewtonian.h)
add_sources(KRPointLight.cpp)
add_sources(KRRenderSettings.cpp)
add_sources(KRResource+blend.cpp)
# add_sources(KRResource+fbx.cpp) # TODO - Locate FBX SDK dependencies
add_sources(KRResource+obj.cpp)
add_sources(KRResource.cpp)
add_sources(KRReverbZone.cpp)
add_sources(KRScene.cpp)
add_sources(KRShader.cpp)
add_sources(KRShaderManager.cpp)
add_sources(KRSpotLight.cpp)
add_sources(KRSprite.cpp)
add_sources(KRTexture.cpp)
add_sources(KRTexture2D.cpp)
add_sources(KRTextureAnimated.cpp)
add_sources(KRTextureCube.cpp)
add_sources(KRTextureKTX.cpp)
add_sources(KRTextureManager.cpp)
add_sources(KRTexturePVR.cpp)
add_sources(KRTextureTGA.cpp)
add_sources(KRUnknown.cpp)
add_sources(KRUnknownManager.cpp)
add_sources(KRViewport.cpp)
include_directories(public)
add_subdirectory(public)
set(KRAKEN_PUBLIC_HEADERS "${KRAKEN_PUBLIC_HEADERS}" PARENT_SCOPE)
# Private Implementation
add_sources(KRAmbientZone.cpp)
add_sources(KRAnimation.cpp)
add_sources(KRAnimationAttribute.cpp)
add_sources(KRAnimationCurve.cpp)
add_sources(KRAnimationCurveManager.cpp)
add_sources(KRAnimationLayer.cpp)
add_sources(KRAnimationManager.cpp)
add_sources(KRAudioBuffer.cpp)
add_sources(KRAudioManager.cpp)
add_sources(KRAudioSample.cpp)
add_sources(KRAudioSource.cpp)
add_sources(KRBehavior.cpp)
add_sources(KRBone.cpp)
add_sources(KRBundle.cpp)
add_sources(KRBundleManager.cpp)
add_sources(KRCamera.cpp)
add_sources(KRCollider.cpp)
add_sources(KRContext.cpp)
IF(APPLE)
add_sources(KREngine.mm)
add_sources(KRStreamer.mm)
IF(IOS)
add_sources(KRContext_ios.mm)
ELSE()
add_sources(KRContext_osx.mm)
ENDIF()
ENDIF (APPLE)
add_sources(KRContextObject.cpp)
add_sources(KRDataBlock.cpp)
add_sources(KRDirectionalLight.cpp)
IF(APPLE)
add_sources(KRDSP_vDSP.cpp)
ELSE()
add_sources(KRDSP_slow.cpp)
ENDIF()
add_sources(KRHelpers.cpp)
add_sources(KRLight.cpp)
add_sources(KRLocator.cpp)
add_sources(KRLODGroup.cpp)
add_sources(KRLODSet.cpp)
add_sources(KRMaterial.cpp)
add_sources(KRMaterialManager.cpp)
add_sources(KRMesh.cpp)
add_sources(KRMeshCube.cpp)
add_sources(KRMeshManager.cpp)
add_sources(KRMeshQuad.cpp)
add_sources(KRMeshSphere.cpp)
add_sources(KRModel.cpp)
add_sources(KRNode.cpp)
add_sources(KROctree.cpp)
add_sources(KROctreeNode.cpp)
add_sources(KRParticleSystem.cpp)
add_sources(KRParticleSystemNewtonian.h)
add_sources(KRPointLight.cpp)
add_sources(KRRenderSettings.cpp)
add_sources(KRResource+blend.cpp)
# add_sources(KRResource+fbx.cpp) # TODO - Locate FBX SDK dependencies
add_sources(KRResource+obj.cpp)
add_sources(KRResource.cpp)
add_sources(KRReverbZone.cpp)
add_sources(KRScene.cpp)
add_sources(KRShader.cpp)
add_sources(KRShaderManager.cpp)
add_sources(KRSpotLight.cpp)
add_sources(KRSprite.cpp)
add_sources(KRTexture.cpp)
add_sources(KRTexture2D.cpp)
add_sources(KRTextureAnimated.cpp)
add_sources(KRTextureCube.cpp)
add_sources(KRTextureKTX.cpp)
add_sources(KRTextureManager.cpp)
add_sources(KRTexturePVR.cpp)
add_sources(KRTextureTGA.cpp)
add_sources(KRUnknown.cpp)
add_sources(KRUnknownManager.cpp)
add_sources(KRViewport.cpp)

View File

@@ -1,167 +1,167 @@
//
// KRAmbientZone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRAmbientZone.h"
#include "KRContext.h"
KRAmbientZone::KRAmbientZone(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_ambient = "";
m_ambient_gain = 1.0f;
m_gradient_distance = 0.25f;
}
KRAmbientZone::~KRAmbientZone()
{
}
std::string KRAmbientZone::getElementName() {
return "ambient_zone";
}
tinyxml2::XMLElement *KRAmbientZone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("zone", m_zone.c_str());
e->SetAttribute("sample", m_ambient.c_str());
e->SetAttribute("gain", m_ambient_gain);
e->SetAttribute("gradient", m_gradient_distance);
return e;
}
void KRAmbientZone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_zone = e->Attribute("zone");
m_gradient_distance = 0.25f;
if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) {
m_gradient_distance = 0.25f;
}
m_ambient = e->Attribute("sample");
m_ambient_gain = 1.0f;
if(e->QueryFloatAttribute("gain", &m_ambient_gain) != tinyxml2::XML_SUCCESS) {
m_ambient_gain = 1.0f;
}
}
std::string KRAmbientZone::getAmbient()
{
return m_ambient;
}
void KRAmbientZone::setAmbient(const std::string &ambient)
{
m_ambient = ambient;
}
float KRAmbientZone::getAmbientGain()
{
return m_ambient_gain;
}
void KRAmbientZone::setAmbientGain(float ambient_gain)
{
m_ambient_gain = ambient_gain;
}
std::string KRAmbientZone::getZone()
{
return m_zone;
}
void KRAmbientZone::setZone(const std::string &zone)
{
m_zone = zone;
}
void KRAmbientZone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_SIREN_AMBIENT_ZONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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));
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
float KRAmbientZone::getGradientDistance()
{
return m_gradient_distance;
}
void KRAmbientZone::setGradientDistance(float gradient_distance)
{
m_gradient_distance = gradient_distance;
}
AABB KRAmbientZone::getBounds() {
// Ambient zones always have a -1, -1, -1 to 1, 1, 1 bounding box
return AABB(-Vector3::One(), Vector3::One(), getModelMatrix());
}
float KRAmbientZone::getContainment(const Vector3 &pos)
{
AABB bounds = getBounds();
if(bounds.contains(pos)) {
Vector3 size = bounds.size();
Vector3 diff = pos - bounds.center();
diff = diff * 2.0f;
diff = Vector3(diff.x / size.x, diff.y / size.y, diff.z / size.z);
float d = diff.magnitude();
if(m_gradient_distance <= 0.0f) {
// Avoid division by zero
d = d > 1.0f ? 0.0f : 1.0f;
} else {
d = (1.0f - d) / m_gradient_distance;
d = KRCLAMP(d, 0.0f, 1.0f);
}
return d;
} else {
return 0.0f;
}
//
// KRAmbientZone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRAmbientZone.h"
#include "KRContext.h"
KRAmbientZone::KRAmbientZone(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_ambient = "";
m_ambient_gain = 1.0f;
m_gradient_distance = 0.25f;
}
KRAmbientZone::~KRAmbientZone()
{
}
std::string KRAmbientZone::getElementName() {
return "ambient_zone";
}
tinyxml2::XMLElement *KRAmbientZone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("zone", m_zone.c_str());
e->SetAttribute("sample", m_ambient.c_str());
e->SetAttribute("gain", m_ambient_gain);
e->SetAttribute("gradient", m_gradient_distance);
return e;
}
void KRAmbientZone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_zone = e->Attribute("zone");
m_gradient_distance = 0.25f;
if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) {
m_gradient_distance = 0.25f;
}
m_ambient = e->Attribute("sample");
m_ambient_gain = 1.0f;
if(e->QueryFloatAttribute("gain", &m_ambient_gain) != tinyxml2::XML_SUCCESS) {
m_ambient_gain = 1.0f;
}
}
std::string KRAmbientZone::getAmbient()
{
return m_ambient;
}
void KRAmbientZone::setAmbient(const std::string &ambient)
{
m_ambient = ambient;
}
float KRAmbientZone::getAmbientGain()
{
return m_ambient_gain;
}
void KRAmbientZone::setAmbientGain(float ambient_gain)
{
m_ambient_gain = ambient_gain;
}
std::string KRAmbientZone::getZone()
{
return m_zone;
}
void KRAmbientZone::setZone(const std::string &zone)
{
m_zone = zone;
}
void KRAmbientZone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_SIREN_AMBIENT_ZONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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));
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
float KRAmbientZone::getGradientDistance()
{
return m_gradient_distance;
}
void KRAmbientZone::setGradientDistance(float gradient_distance)
{
m_gradient_distance = gradient_distance;
}
AABB KRAmbientZone::getBounds() {
// Ambient zones always have a -1, -1, -1 to 1, 1, 1 bounding box
return AABB::Create(-Vector3::One(), Vector3::One(), getModelMatrix());
}
float KRAmbientZone::getContainment(const Vector3 &pos)
{
AABB bounds = getBounds();
if(bounds.contains(pos)) {
Vector3 size = bounds.size();
Vector3 diff = pos - bounds.center();
diff = diff * 2.0f;
diff = Vector3::Create(diff.x / size.x, diff.y / size.y, diff.z / size.z);
float d = diff.magnitude();
if(m_gradient_distance <= 0.0f) {
// Avoid division by zero
d = d > 1.0f ? 0.0f : 1.0f;
} else {
d = (1.0f - d) / m_gradient_distance;
d = KRCLAMP(d, 0.0f, 1.0f);
}
return d;
} else {
return 0.0f;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,97 +1,97 @@
//
// KRBone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRBone.h"
#include "KRContext.h"
KRBone::KRBone(KRScene &scene, std::string name) : KRNode(scene, name)
{
setScaleCompensation(true);
}
KRBone::~KRBone()
{
}
std::string KRBone::getElementName() {
return "bone";
}
tinyxml2::XMLElement *KRBone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
return e;
}
void KRBone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
setScaleCompensation(true);
}
AABB KRBone::getBounds() {
return AABB(-Vector3::One(), Vector3::One(), getModelMatrix()); // Only required for bone debug visualization
}
void KRBone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_BONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
}
}
void KRBone::setBindPose(const Matrix4 &pose)
{
m_bind_pose = pose;
}
const Matrix4 &KRBone::getBindPose()
{
return m_bind_pose;
}
//
// KRBone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRBone.h"
#include "KRContext.h"
KRBone::KRBone(KRScene &scene, std::string name) : KRNode(scene, name)
{
setScaleCompensation(true);
}
KRBone::~KRBone()
{
}
std::string KRBone::getElementName() {
return "bone";
}
tinyxml2::XMLElement *KRBone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
return e;
}
void KRBone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
setScaleCompensation(true);
}
AABB KRBone::getBounds() {
return AABB::Create(-Vector3::One(), Vector3::One(), getModelMatrix()); // Only required for bone debug visualization
}
void KRBone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_BONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
}
}
void KRBone::setBindPose(const Matrix4 &pose)
{
m_bind_pose = pose;
}
const Matrix4 &KRBone::getBindPose()
{
return m_bind_pose;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,229 +1,229 @@
//
// 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.
//
#include "KREngine-common.h"
#include "KRCollider.h"
#include "KRContext.h"
#include "KRMesh.h"
KRCollider::KRCollider(KRScene &scene, std::string collider_name, std::string model_name, unsigned int layer_mask, float audio_occlusion) : KRNode(scene, collider_name) {
m_model_name = model_name;
m_layer_mask = layer_mask;
m_audio_occlusion = audio_occlusion;
}
KRCollider::~KRCollider() {
}
std::string KRCollider::getElementName() {
return "collider";
}
tinyxml2::XMLElement *KRCollider::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("mesh", m_model_name.c_str());
e->SetAttribute("layer_mask", m_layer_mask);
e->SetAttribute("audio_occlusion", m_audio_occlusion);
return e;
}
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;
}
}
void KRCollider::loadModel() {
if(m_models.size() == 0) {
m_models = m_pContext->getMeshManager()->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);
}
}
}
AABB KRCollider::getBounds() {
loadModel();
if(m_models.size() > 0) {
return AABB(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
} else {
return AABB::Infinite();
}
}
bool KRCollider::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
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)) {
Vector3 v0_model_space = Matrix4::Dot(getInverseModelMatrix(), v0);
Vector3 v1_model_space = Matrix4::Dot(getInverseModelMatrix(), v1);
HitInfo hitinfo_model_space;
if(hitinfo.didHit()) {
Vector3 hit_position_model_space = Matrix4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
hitinfo_model_space = HitInfo(hit_position_model_space, Matrix4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
}
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
Vector3 hit_position_world_space = Matrix4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
hitinfo = HitInfo(hit_position_world_space, Vector3::Normalize(Matrix4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
return true;
}
}
}
}
return false;
}
bool KRCollider::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
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)) {
Vector3 v0_model_space = Matrix4::Dot(getInverseModelMatrix(), v0);
Vector3 dir_model_space = Vector3::Normalize(Matrix4::DotNoTranslate(getInverseModelMatrix(), dir));
HitInfo hitinfo_model_space;
if(hitinfo.didHit()) {
Vector3 hit_position_model_space = Matrix4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
hitinfo_model_space = HitInfo(hit_position_model_space, Vector3::Normalize(Matrix4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
}
if(m_models[0]->rayCast(v0_model_space, dir_model_space, hitinfo_model_space)) {
Vector3 hit_position_world_space = Matrix4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
hitinfo = HitInfo(hit_position_world_space, Vector3::Normalize(Matrix4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
return true;
}
}
}
}
return false;
}
bool KRCollider::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
if(layer_mask & m_layer_mask) { // Only test if layer masks have a common bit set
loadModel();
if(m_models.size()) {
AABB sphereCastBounds = AABB( // TODO - Need to cache this; perhaps encasulate within a "spherecast" class to be passed through these functions
Vector3(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius),
Vector3(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius)
);
if(getBounds().intersects(sphereCastBounds)) {
if(m_models[0]->sphereCast(getModelMatrix(), v0, v1, radius, hitinfo)) {
hitinfo = HitInfo(hitinfo.getPosition(), hitinfo.getNormal(), hitinfo.getDistance(), this);
return true;
}
}
}
}
return false;
}
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;
}
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)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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", 1.0f);
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
GL_POP_GROUP_MARKER;
}
}
}
//
// 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.
//
#include "KREngine-common.h"
#include "KRCollider.h"
#include "KRContext.h"
#include "KRMesh.h"
KRCollider::KRCollider(KRScene &scene, std::string collider_name, std::string model_name, unsigned int layer_mask, float audio_occlusion) : KRNode(scene, collider_name) {
m_model_name = model_name;
m_layer_mask = layer_mask;
m_audio_occlusion = audio_occlusion;
}
KRCollider::~KRCollider() {
}
std::string KRCollider::getElementName() {
return "collider";
}
tinyxml2::XMLElement *KRCollider::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("mesh", m_model_name.c_str());
e->SetAttribute("layer_mask", m_layer_mask);
e->SetAttribute("audio_occlusion", m_audio_occlusion);
return e;
}
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;
}
}
void KRCollider::loadModel() {
if(m_models.size() == 0) {
m_models = m_pContext->getMeshManager()->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);
}
}
}
AABB KRCollider::getBounds() {
loadModel();
if(m_models.size() > 0) {
return AABB::Create(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
} else {
return AABB::Infinite();
}
}
bool KRCollider::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
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)) {
Vector3 v0_model_space = Matrix4::Dot(getInverseModelMatrix(), v0);
Vector3 v1_model_space = Matrix4::Dot(getInverseModelMatrix(), v1);
HitInfo hitinfo_model_space;
if(hitinfo.didHit()) {
Vector3 hit_position_model_space = Matrix4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
hitinfo_model_space = HitInfo(hit_position_model_space, Matrix4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
}
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
Vector3 hit_position_world_space = Matrix4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
hitinfo = HitInfo(hit_position_world_space, Vector3::Normalize(Matrix4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
return true;
}
}
}
}
return false;
}
bool KRCollider::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
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)) {
Vector3 v0_model_space = Matrix4::Dot(getInverseModelMatrix(), v0);
Vector3 dir_model_space = Vector3::Normalize(Matrix4::DotNoTranslate(getInverseModelMatrix(), dir));
HitInfo hitinfo_model_space;
if(hitinfo.didHit()) {
Vector3 hit_position_model_space = Matrix4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
hitinfo_model_space = HitInfo(hit_position_model_space, Vector3::Normalize(Matrix4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
}
if(m_models[0]->rayCast(v0_model_space, dir_model_space, hitinfo_model_space)) {
Vector3 hit_position_world_space = Matrix4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
hitinfo = HitInfo(hit_position_world_space, Vector3::Normalize(Matrix4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
return true;
}
}
}
}
return false;
}
bool KRCollider::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
if(layer_mask & m_layer_mask) { // Only test if layer masks have a common bit set
loadModel();
if(m_models.size()) {
AABB sphereCastBounds = AABB::Create( // TODO - Need to cache this; perhaps encasulate within a "spherecast" class to be passed through these functions
Vector3::Create(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius),
Vector3::Create(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius)
);
if(getBounds().intersects(sphereCastBounds)) {
if(m_models[0]->sphereCast(getModelMatrix(), v0, v1, radius, hitinfo)) {
hitinfo = HitInfo(hitinfo.getPosition(), hitinfo.getNormal(), hitinfo.getDistance(), this);
return true;
}
}
}
}
return false;
}
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;
}
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)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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", 1.0f);
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
GL_POP_GROUP_MARKER;
}
}
}

View File

@@ -1,207 +1,207 @@
//
// KREngine.h
// 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.
//
#include "KRDSP.h"
#ifdef KRDSP_SLOW
#include "KREngine-common.h"
namespace KRDSP {
FFTWorkspace::FFTWorkspace()
{
sin_table = nullptr;
cos_table = nullptr;
}
FFTWorkspace::~FFTWorkspace()
{
destroy();
}
void FFTWorkspace::create(size_t length)
{
size_t size = (length / 2);
cos_table = new float[size];
sin_table = new float[size];
for (int i = 0; i < size / 2; i++) {
float a = 2 * M_PI * i / length;
cos_table[i] = cos(a);
sin_table[i] = sin(a);
}
}
void FFTWorkspace::destroy()
{
if (sin_table) {
delete sin_table;
sin_table = nullptr;
}
if (cos_table) {
delete cos_table;
cos_table = nullptr;
}
}
void FFTForward(const FFTWorkspace &workspace, SplitComplex *src, size_t count)
{
// Radix-2 Decimation in Time FFT Algorithm
// http://en.dsplib.org/content/fft_dec_in_time.html
// Only power-of-two sizes supported
assert((count & (count - 1)) == 0);
int levels = 0;
while (1 << levels <= count) {
levels++;
}
for (size_t i = 0; i < count; i++) {
size_t j = 0;
for (int k = 0; k < levels; k++) {
j <<= 1;
j |= ((i >> k) & 1);
}
if (j > i) {
float temp = src->realp[i];
src->realp[i] = src->realp[j];
src->realp[j] = temp;
temp = src->imagp[i];
src->imagp[i] = src->imagp[j];
src->imagp[j] = temp;
}
}
for (size_t size = 2; size <= count; size *= 2) {
size_t halfsize = size / 2;
size_t step = count / size;
for (size_t i = 0; i < count; i += size) {
for (size_t j = i, k = 0; j < i + halfsize; j++, k += step) {
float temp_real = src->realp[j + halfsize] * workspace.cos_table[k];
temp_real += src->imagp[j + halfsize] * workspace.sin_table[k];
float temp_imag = -src->realp[j + halfsize] * workspace.sin_table[k];
temp_imag += src->imagp[j + halfsize] * workspace.cos_table[k];
src->realp[j + halfsize] = src->realp[j] - temp_real;
src->imagp[j + halfsize] = src->imagp[j] - temp_imag;
src->realp[j] += temp_real;
src->imagp[j] += temp_imag;
}
}
}
}
void FFTInverse(const FFTWorkspace &workspace, SplitComplex *src, size_t count)
{
SplitComplex swapped;
swapped.imagp = src->realp;
swapped.realp = src->imagp;
FFTForward(workspace, &swapped, count);
}
void Int16ToFloat(const short *src, size_t srcStride, float *dest, size_t destStride, size_t count)
{
const short *r = src;
float *w = dest;
while (w < dest + destStride * count) {
*w = (float)*r;
r += srcStride;
w += destStride;
}
}
void Scale(float *buffer, float scale, size_t count)
{
float *w = buffer;
while (w < buffer + count) {
*w *= scale;
w++;
}
}
void ScaleCopy(const float *src, float scale, float *dest, size_t count)
{
const float *r = src;
float *w = dest;
while (w < dest + count) {
*w = *r * scale;
w++;
r++;
}
}
void ScaleCopy(const SplitComplex *src, float scale, SplitComplex *dest, size_t count)
{
ScaleCopy(src->realp, scale, dest->realp, count);
ScaleCopy(src->imagp, scale, dest->imagp, count);
}
void ScaleRamp(float *buffer, float scaleStart, float scaleStep, size_t count)
{
float *w = buffer;
float s = scaleStart;
while (w < buffer + count) {
*w *= s;
w++;
s += scaleStep;
}
}
void Accumulate(float *buffer, size_t bufferStride, const float *buffer2, size_t buffer2Stride, size_t count)
{
float *w = buffer;
const float *r = buffer2;
while (w < buffer + bufferStride * count) {
*w *= *r;
w += bufferStride;
r += buffer2Stride;
}
}
void Accumulate(SplitComplex *buffer, const SplitComplex *buffer2, size_t count)
{
for (size_t i = 0; i < count; i++) {
buffer->imagp[i] += buffer2->imagp[i];
buffer->realp[i] += buffer2->realp[i];
}
}
void Multiply(const SplitComplex *a, const SplitComplex *b, SplitComplex *c, size_t count)
{
for (size_t i = 0; i < count; i++) {
c->realp[i] = a->realp[i] * b->realp[i] - a->imagp[i] * b->imagp[i];
c->imagp[i] = a->realp[i] * b->imagp[i] + a->imagp[i] * b->realp[i];
}
}
} // namespace KRDSP
#endif // KRDSP_SLOW
//
// KREngine.h
// 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.
//
#include "KRDSP.h"
#ifdef KRDSP_SLOW
#include "KREngine-common.h"
namespace KRDSP {
FFTWorkspace::FFTWorkspace()
{
sin_table = nullptr;
cos_table = nullptr;
}
FFTWorkspace::~FFTWorkspace()
{
destroy();
}
void FFTWorkspace::create(size_t length)
{
size_t size = (length / 2);
cos_table = new float[size];
sin_table = new float[size];
for (int i = 0; i < size / 2; i++) {
float a = 2.0f * M_PI * i / length;
cos_table[i] = cos(a);
sin_table[i] = sin(a);
}
}
void FFTWorkspace::destroy()
{
if (sin_table) {
delete sin_table;
sin_table = nullptr;
}
if (cos_table) {
delete cos_table;
cos_table = nullptr;
}
}
void FFTForward(const FFTWorkspace &workspace, SplitComplex *src, size_t count)
{
// Radix-2 Decimation in Time FFT Algorithm
// http://en.dsplib.org/content/fft_dec_in_time.html
// Only power-of-two sizes supported
assert((count & (count - 1)) == 0);
int levels = 0;
while (1 << levels <= count) {
levels++;
}
for (size_t i = 0; i < count; i++) {
size_t j = 0;
for (int k = 0; k < levels; k++) {
j <<= 1;
j |= ((i >> k) & 1);
}
if (j > i) {
float temp = src->realp[i];
src->realp[i] = src->realp[j];
src->realp[j] = temp;
temp = src->imagp[i];
src->imagp[i] = src->imagp[j];
src->imagp[j] = temp;
}
}
for (size_t size = 2; size <= count; size *= 2) {
size_t halfsize = size / 2;
size_t step = count / size;
for (size_t i = 0; i < count; i += size) {
for (size_t j = i, k = 0; j < i + halfsize; j++, k += step) {
float temp_real = src->realp[j + halfsize] * workspace.cos_table[k];
temp_real += src->imagp[j + halfsize] * workspace.sin_table[k];
float temp_imag = -src->realp[j + halfsize] * workspace.sin_table[k];
temp_imag += src->imagp[j + halfsize] * workspace.cos_table[k];
src->realp[j + halfsize] = src->realp[j] - temp_real;
src->imagp[j + halfsize] = src->imagp[j] - temp_imag;
src->realp[j] += temp_real;
src->imagp[j] += temp_imag;
}
}
}
}
void FFTInverse(const FFTWorkspace &workspace, SplitComplex *src, size_t count)
{
SplitComplex swapped;
swapped.imagp = src->realp;
swapped.realp = src->imagp;
FFTForward(workspace, &swapped, count);
}
void Int16ToFloat(const short *src, size_t srcStride, float *dest, size_t destStride, size_t count)
{
const short *r = src;
float *w = dest;
while (w < dest + destStride * count) {
*w = (float)*r;
r += srcStride;
w += destStride;
}
}
void Scale(float *buffer, float scale, size_t count)
{
float *w = buffer;
while (w < buffer + count) {
*w *= scale;
w++;
}
}
void ScaleCopy(const float *src, float scale, float *dest, size_t count)
{
const float *r = src;
float *w = dest;
while (w < dest + count) {
*w = *r * scale;
w++;
r++;
}
}
void ScaleCopy(const SplitComplex *src, float scale, SplitComplex *dest, size_t count)
{
ScaleCopy(src->realp, scale, dest->realp, count);
ScaleCopy(src->imagp, scale, dest->imagp, count);
}
void ScaleRamp(float *buffer, float scaleStart, float scaleStep, size_t count)
{
float *w = buffer;
float s = scaleStart;
while (w < buffer + count) {
*w *= s;
w++;
s += scaleStep;
}
}
void Accumulate(float *buffer, size_t bufferStride, const float *buffer2, size_t buffer2Stride, size_t count)
{
float *w = buffer;
const float *r = buffer2;
while (w < buffer + bufferStride * count) {
*w *= *r;
w += bufferStride;
r += buffer2Stride;
}
}
void Accumulate(SplitComplex *buffer, const SplitComplex *buffer2, size_t count)
{
for (size_t i = 0; i < count; i++) {
buffer->imagp[i] += buffer2->imagp[i];
buffer->realp[i] += buffer2->realp[i];
}
}
void Multiply(const SplitComplex *a, const SplitComplex *b, SplitComplex *c, size_t count)
{
for (size_t i = 0; i < count; i++) {
c->realp[i] = a->realp[i] * b->realp[i] - a->imagp[i] * b->imagp[i];
c->imagp[i] = a->realp[i] * b->imagp[i] + a->imagp[i] * b->realp[i];
}
}
} // namespace KRDSP
#endif // KRDSP_SLOW

View File

@@ -1,135 +1,135 @@
//
// KRDirectionalLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRDirectionalLight.h"
#include "KRShader.h"
#include "KRContext.h"
#include "assert.h"
#include "KRStockGeometry.h"
KRDirectionalLight::KRDirectionalLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
}
KRDirectionalLight::~KRDirectionalLight()
{
}
std::string KRDirectionalLight::getElementName() {
return "directional_light";
}
Vector3 KRDirectionalLight::getWorldLightDirection() {
return Matrix4::Dot(getWorldRotation().rotationMatrix(), getLocalLightDirection());
}
Vector3 KRDirectionalLight::getLocalLightDirection() {
return Vector3::Up(); //&KRF HACK changed from Vector3::Forward(); - to compensate for the way Maya handles post rotation.
}
int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewport) {
const float KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE = 1.25f; // Scale to apply to view frustrum bounds so that we don't need to refresh shadows on every frame
int cShadows = 1;
for(int iShadow=0; iShadow < cShadows; iShadow++) {
/*
TODO - Determine if we still need this...
GLfloat shadowMinDepths[3][3] = {{0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f},{0.0f, 0.05f, 0.3f}};
GLfloat shadowMaxDepths[3][3] = {{0.0f, 0.0f, 1.0f},{0.1f, 0.0f, 0.0f},{0.1f, 0.3f, 1.0f}};
float min_depth = 0.0f;
float max_depth = 1.0f;
*/
AABB worldSpacefrustrumSliceBounds = AABB(Vector3(-1.0f, -1.0f, -1.0f), Vector3(1.0f, 1.0f, 1.0f), Matrix4::Invert(viewport.getViewProjectionMatrix()));
worldSpacefrustrumSliceBounds.scale(KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
Vector3 shadowLook = -Vector3::Normalize(getWorldLightDirection());
Vector3 shadowUp(0.0, 1.0, 0.0);
if(Vector3::Dot(shadowUp, shadowLook) > 0.99f) shadowUp = Vector3(0.0, 0.0, 1.0); // Ensure shadow look direction is not parallel with the shadowUp direction
// Matrix4 matShadowView = Matrix4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp);
// Matrix4 matShadowProjection = Matrix4();
// matShadowProjection.scale(0.001, 0.001, 0.001);
Matrix4 matShadowView = Matrix4::LookAt(worldSpacefrustrumSliceBounds.center() - shadowLook, worldSpacefrustrumSliceBounds.center(), shadowUp);
Matrix4 matShadowProjection = Matrix4();
AABB shadowSpaceFrustrumSliceBounds = AABB(worldSpacefrustrumSliceBounds.min, worldSpacefrustrumSliceBounds.max, Matrix4::Invert(matShadowProjection));
AABB shadowSpaceSceneBounds = AABB(getScene().getRootOctreeBounds().min, getScene().getRootOctreeBounds().max, Matrix4::Invert(matShadowProjection));
if(shadowSpaceSceneBounds.min.z < shadowSpaceFrustrumSliceBounds.min.z) shadowSpaceFrustrumSliceBounds.min.z = shadowSpaceSceneBounds.min.z; // Include any potential shadow casters that are outside the view frustrum
matShadowProjection.scale(1.0f / shadowSpaceFrustrumSliceBounds.size().x, 1.0f / shadowSpaceFrustrumSliceBounds.size().y, 1.0f / shadowSpaceFrustrumSliceBounds.size().z);
Matrix4 matBias;
matBias.bias();
matShadowProjection *= matBias;
KRViewport newShadowViewport = KRViewport(Vector2(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection);
AABB prevShadowBounds = AABB(-Vector3::One(), Vector3::One(), Matrix4::Invert(m_shadowViewports[iShadow].getViewProjectionMatrix()));
AABB minimumShadowBounds = AABB(-Vector3::One(), Vector3::One(), Matrix4::Invert(newShadowViewport.getViewProjectionMatrix()));
minimumShadowBounds.scale(1.0f / KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
if(!prevShadowBounds.contains(minimumShadowBounds) || !shadowValid[iShadow] || true) { // FINDME, HACK - Re-generating the shadow map every frame. This should only be needed if the shadow contains non-static geometry
m_shadowViewports[iShadow] = newShadowViewport;
shadowValid[iShadow] = false;
fprintf(stderr, "Kraken - Generate shadow maps...\n");
}
}
return 1;
}
void KRDirectionalLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRLight::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_DEFERRED_LIGHTS) {
// Lights are rendered on the second pass of the deferred renderer
std::vector<KRDirectionalLight *> this_light;
this_light.push_back(this);
Matrix4 matModelViewInverseTranspose = viewport.getViewMatrix() * getModelMatrix();
matModelViewInverseTranspose.transpose();
matModelViewInverseTranspose.invert();
Vector3 light_direction_view_space = getWorldLightDirection();
light_direction_view_space = Matrix4::Dot(matModelViewInverseTranspose, light_direction_view_space);
light_direction_view_space.normalize();
KRShader *pShader = getContext().getShaderManager()->getShader("light_directional", pCamera, std::vector<KRPointLight *>(), this_light, std::vector<KRSpotLight *>(), 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(), std::vector<KRPointLight *>(), this_light, std::vector<KRSpotLight *>(), 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_DIRECTION_VIEW_SPACE, light_direction_view_space);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_INTENSITY, m_intensity * 0.01f);
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
// Render a full screen quad
m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
AABB KRDirectionalLight::getBounds()
{
return AABB::Infinite();
}
//
// KRDirectionalLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRDirectionalLight.h"
#include "KRShader.h"
#include "KRContext.h"
#include "assert.h"
#include "KRStockGeometry.h"
KRDirectionalLight::KRDirectionalLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
}
KRDirectionalLight::~KRDirectionalLight()
{
}
std::string KRDirectionalLight::getElementName() {
return "directional_light";
}
Vector3 KRDirectionalLight::getWorldLightDirection() {
return Matrix4::Dot(getWorldRotation().rotationMatrix(), getLocalLightDirection());
}
Vector3 KRDirectionalLight::getLocalLightDirection() {
return Vector3::Up(); //&KRF HACK changed from Vector3::Forward(); - to compensate for the way Maya handles post rotation.
}
int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewport) {
const float KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE = 1.25f; // Scale to apply to view frustrum bounds so that we don't need to refresh shadows on every frame
int cShadows = 1;
for(int iShadow=0; iShadow < cShadows; iShadow++) {
/*
TODO - Determine if we still need this...
GLfloat shadowMinDepths[3][3] = {{0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f},{0.0f, 0.05f, 0.3f}};
GLfloat shadowMaxDepths[3][3] = {{0.0f, 0.0f, 1.0f},{0.1f, 0.0f, 0.0f},{0.1f, 0.3f, 1.0f}};
float min_depth = 0.0f;
float max_depth = 1.0f;
*/
AABB worldSpacefrustrumSliceBounds = AABB::Create(Vector3::Create(-1.0f, -1.0f, -1.0f), Vector3::Create(1.0f, 1.0f, 1.0f), Matrix4::Invert(viewport.getViewProjectionMatrix()));
worldSpacefrustrumSliceBounds.scale(KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
Vector3 shadowLook = -Vector3::Normalize(getWorldLightDirection());
Vector3 shadowUp = Vector3::Create(0.0, 1.0, 0.0);
if(Vector3::Dot(shadowUp, shadowLook) > 0.99f) shadowUp = Vector3::Create(0.0, 0.0, 1.0); // Ensure shadow look direction is not parallel with the shadowUp direction
// Matrix4 matShadowView = Matrix4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp);
// Matrix4 matShadowProjection = Matrix4();
// matShadowProjection.scale(0.001, 0.001, 0.001);
Matrix4 matShadowView = Matrix4::LookAt(worldSpacefrustrumSliceBounds.center() - shadowLook, worldSpacefrustrumSliceBounds.center(), shadowUp);
Matrix4 matShadowProjection = Matrix4();
AABB shadowSpaceFrustrumSliceBounds = AABB::Create(worldSpacefrustrumSliceBounds.min, worldSpacefrustrumSliceBounds.max, Matrix4::Invert(matShadowProjection));
AABB shadowSpaceSceneBounds = AABB::Create(getScene().getRootOctreeBounds().min, getScene().getRootOctreeBounds().max, Matrix4::Invert(matShadowProjection));
if(shadowSpaceSceneBounds.min.z < shadowSpaceFrustrumSliceBounds.min.z) shadowSpaceFrustrumSliceBounds.min.z = shadowSpaceSceneBounds.min.z; // Include any potential shadow casters that are outside the view frustrum
matShadowProjection.scale(1.0f / shadowSpaceFrustrumSliceBounds.size().x, 1.0f / shadowSpaceFrustrumSliceBounds.size().y, 1.0f / shadowSpaceFrustrumSliceBounds.size().z);
Matrix4 matBias;
matBias.bias();
matShadowProjection *= matBias;
KRViewport newShadowViewport = KRViewport(Vector2::Create(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection);
AABB prevShadowBounds = AABB::Create(-Vector3::One(), Vector3::One(), Matrix4::Invert(m_shadowViewports[iShadow].getViewProjectionMatrix()));
AABB minimumShadowBounds = AABB::Create(-Vector3::One(), Vector3::One(), Matrix4::Invert(newShadowViewport.getViewProjectionMatrix()));
minimumShadowBounds.scale(1.0f / KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
if(!prevShadowBounds.contains(minimumShadowBounds) || !shadowValid[iShadow] || true) { // FINDME, HACK - Re-generating the shadow map every frame. This should only be needed if the shadow contains non-static geometry
m_shadowViewports[iShadow] = newShadowViewport;
shadowValid[iShadow] = false;
fprintf(stderr, "Kraken - Generate shadow maps...\n");
}
}
return 1;
}
void KRDirectionalLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRLight::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_DEFERRED_LIGHTS) {
// Lights are rendered on the second pass of the deferred renderer
std::vector<KRDirectionalLight *> this_light;
this_light.push_back(this);
Matrix4 matModelViewInverseTranspose = viewport.getViewMatrix() * getModelMatrix();
matModelViewInverseTranspose.transpose();
matModelViewInverseTranspose.invert();
Vector3 light_direction_view_space = getWorldLightDirection();
light_direction_view_space = Matrix4::Dot(matModelViewInverseTranspose, light_direction_view_space);
light_direction_view_space.normalize();
KRShader *pShader = getContext().getShaderManager()->getShader("light_directional", pCamera, std::vector<KRPointLight *>(), this_light, std::vector<KRSpotLight *>(), 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(), std::vector<KRPointLight *>(), this_light, std::vector<KRSpotLight *>(), 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_DIRECTION_VIEW_SPACE, light_direction_view_space);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_INTENSITY, m_intensity * 0.01f);
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
// Render a full screen quad
m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
AABB KRDirectionalLight::getBounds()
{
return AABB::Infinite();
}

View File

@@ -15,6 +15,8 @@
#include "KRHelpers.h"
using namespace kraken;
#include "hydra.h"
#include <stdint.h>
#include <vector>
#include <string>

View File

@@ -1,6 +1,10 @@
#ifndef KRHELPERS_H
#define KRHELPERS_H
#include "vector2.h"
#include "vector3.h"
#include "matrix4.h"
#if defined(_WIN32) || defined(_WIN64)
#include <glad/glad.h>
#elif defined(__linux__) || defined(__unix__) || defined(__posix__)

View File

@@ -1,173 +1,173 @@
//
// KRLODGroup.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRLODGroup.h"
#include "KRLODSet.h"
#include "KRContext.h"
KRLODGroup::KRLODGroup(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_min_distance = 0.0f;
m_max_distance = 0.0f;
m_reference = AABB(Vector3::Zero(), Vector3::Zero());
m_use_world_units = true;
}
KRLODGroup::~KRLODGroup()
{
}
std::string KRLODGroup::getElementName() {
return "lod_group";
}
tinyxml2::XMLElement *KRLODGroup::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("min_distance", m_min_distance);
e->SetAttribute("max_distance", m_max_distance);
e->SetAttribute("reference_min_x", m_reference.min.x);
e->SetAttribute("reference_min_y", m_reference.min.y);
e->SetAttribute("reference_min_z", m_reference.min.z);
e->SetAttribute("reference_max_x", m_reference.max.x);
e->SetAttribute("reference_max_y", m_reference.max.y);
e->SetAttribute("reference_max_z", m_reference.max.z);
e->SetAttribute("use_world_units", m_use_world_units ? "true" : "false");
return e;
}
void KRLODGroup::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_min_distance = 0.0f;
if(e->QueryFloatAttribute("min_distance", &m_min_distance) != tinyxml2::XML_SUCCESS) {
m_min_distance = 0.0f;
}
m_max_distance = 0.0f;
if(e->QueryFloatAttribute("max_distance", &m_max_distance) != tinyxml2::XML_SUCCESS) {
m_max_distance = 0.0f;
}
float x=0.0f, y=0.0f, z=0.0f;
if(e->QueryFloatAttribute("reference_min_x", &x) != tinyxml2::XML_SUCCESS) {
x = 0.0f;
}
if(e->QueryFloatAttribute("reference_min_y", &y) != tinyxml2::XML_SUCCESS) {
y = 0.0f;
}
if(e->QueryFloatAttribute("reference_min_z", &z) != tinyxml2::XML_SUCCESS) {
z = 0.0f;
}
m_reference.min = Vector3(x,y,z);
x=0.0f; y=0.0f; z=0.0f;
if(e->QueryFloatAttribute("reference_max_x", &x) != tinyxml2::XML_SUCCESS) {
x = 0.0f;
}
if(e->QueryFloatAttribute("reference_max_y", &y) != tinyxml2::XML_SUCCESS) {
y = 0.0f;
}
if(e->QueryFloatAttribute("reference_max_z", &z) != tinyxml2::XML_SUCCESS) {
z = 0.0f;
}
m_reference.max = Vector3(x,y,z);
m_use_world_units = true;
if(e->QueryBoolAttribute("use_world_units", &m_use_world_units) != tinyxml2::XML_SUCCESS) {
m_use_world_units = true;
}
}
const AABB &KRLODGroup::getReference() const
{
return m_reference;
}
void KRLODGroup::setReference(const AABB &reference)
{
m_reference = reference;
}
KRNode::LodVisibility KRLODGroup::calcLODVisibility(const KRViewport &viewport)
{
if(m_min_distance == 0 && m_max_distance == 0) {
return LOD_VISIBILITY_VISIBLE;
} else {
float lod_bias = viewport.getLODBias();
lod_bias = pow(2.0f, -lod_bias);
// Compare using squared distances as sqrt is expensive
float sqr_distance;
float sqr_prestream_distance;
Vector3 world_camera_position = viewport.getCameraPosition();
Vector3 local_camera_position = worldToLocal(world_camera_position);
Vector3 local_reference_point = m_reference.nearestPoint(local_camera_position);
if(m_use_world_units) {
Vector3 world_reference_point = localToWorld(local_reference_point);
sqr_distance = (world_camera_position - world_reference_point).sqrMagnitude() * (lod_bias * lod_bias);
sqr_prestream_distance = getContext().KRENGINE_PRESTREAM_DISTANCE * getContext().KRENGINE_PRESTREAM_DISTANCE;
} else {
sqr_distance = (local_camera_position - local_reference_point).sqrMagnitude() * (lod_bias * lod_bias);
Vector3 world_reference_point = localToWorld(local_reference_point);
sqr_prestream_distance = worldToLocal(Vector3::Normalize(world_reference_point - world_camera_position) * getContext().KRENGINE_PRESTREAM_DISTANCE).sqrMagnitude(); // TODO, FINDME - Optimize with precalc?
}
float sqr_min_visible_distance = m_min_distance * m_min_distance;
float sqr_max_visible_distance = m_max_distance * m_max_distance;
if((sqr_distance >= sqr_min_visible_distance || m_min_distance == 0) && (sqr_distance < sqr_max_visible_distance || m_max_distance == 0)) {
return LOD_VISIBILITY_VISIBLE;
} else if((sqr_distance >= sqr_min_visible_distance - sqr_prestream_distance || m_min_distance == 0) && (sqr_distance < sqr_max_visible_distance + sqr_prestream_distance || m_max_distance == 0)) {
return LOD_VISIBILITY_PRESTREAM;
} else {
return LOD_VISIBILITY_HIDDEN;
}
}
}
float KRLODGroup::getMinDistance()
{
return m_min_distance;
}
float KRLODGroup::getMaxDistance()
{
return m_max_distance;
}
void KRLODGroup::setMinDistance(float min_distance)
{
m_min_distance = min_distance;
}
void KRLODGroup::setMaxDistance(float max_distance)
{
m_max_distance = max_distance;
}
void KRLODGroup::setUseWorldUnits(bool use_world_units)
{
m_use_world_units = use_world_units;
}
bool KRLODGroup::getUseWorldUnits() const
{
return m_use_world_units;
}
//
// KRLODGroup.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRLODGroup.h"
#include "KRLODSet.h"
#include "KRContext.h"
KRLODGroup::KRLODGroup(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_min_distance = 0.0f;
m_max_distance = 0.0f;
m_reference = AABB::Create(Vector3::Zero(), Vector3::Zero());
m_use_world_units = true;
}
KRLODGroup::~KRLODGroup()
{
}
std::string KRLODGroup::getElementName() {
return "lod_group";
}
tinyxml2::XMLElement *KRLODGroup::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("min_distance", m_min_distance);
e->SetAttribute("max_distance", m_max_distance);
e->SetAttribute("reference_min_x", m_reference.min.x);
e->SetAttribute("reference_min_y", m_reference.min.y);
e->SetAttribute("reference_min_z", m_reference.min.z);
e->SetAttribute("reference_max_x", m_reference.max.x);
e->SetAttribute("reference_max_y", m_reference.max.y);
e->SetAttribute("reference_max_z", m_reference.max.z);
e->SetAttribute("use_world_units", m_use_world_units ? "true" : "false");
return e;
}
void KRLODGroup::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_min_distance = 0.0f;
if(e->QueryFloatAttribute("min_distance", &m_min_distance) != tinyxml2::XML_SUCCESS) {
m_min_distance = 0.0f;
}
m_max_distance = 0.0f;
if(e->QueryFloatAttribute("max_distance", &m_max_distance) != tinyxml2::XML_SUCCESS) {
m_max_distance = 0.0f;
}
float x=0.0f, y=0.0f, z=0.0f;
if(e->QueryFloatAttribute("reference_min_x", &x) != tinyxml2::XML_SUCCESS) {
x = 0.0f;
}
if(e->QueryFloatAttribute("reference_min_y", &y) != tinyxml2::XML_SUCCESS) {
y = 0.0f;
}
if(e->QueryFloatAttribute("reference_min_z", &z) != tinyxml2::XML_SUCCESS) {
z = 0.0f;
}
m_reference.min = Vector3::Create(x,y,z);
x=0.0f; y=0.0f; z=0.0f;
if(e->QueryFloatAttribute("reference_max_x", &x) != tinyxml2::XML_SUCCESS) {
x = 0.0f;
}
if(e->QueryFloatAttribute("reference_max_y", &y) != tinyxml2::XML_SUCCESS) {
y = 0.0f;
}
if(e->QueryFloatAttribute("reference_max_z", &z) != tinyxml2::XML_SUCCESS) {
z = 0.0f;
}
m_reference.max = Vector3::Create(x,y,z);
m_use_world_units = true;
if(e->QueryBoolAttribute("use_world_units", &m_use_world_units) != tinyxml2::XML_SUCCESS) {
m_use_world_units = true;
}
}
const AABB &KRLODGroup::getReference() const
{
return m_reference;
}
void KRLODGroup::setReference(const AABB &reference)
{
m_reference = reference;
}
KRNode::LodVisibility KRLODGroup::calcLODVisibility(const KRViewport &viewport)
{
if(m_min_distance == 0 && m_max_distance == 0) {
return LOD_VISIBILITY_VISIBLE;
} else {
float lod_bias = viewport.getLODBias();
lod_bias = pow(2.0f, -lod_bias);
// Compare using squared distances as sqrt is expensive
float sqr_distance;
float sqr_prestream_distance;
Vector3 world_camera_position = viewport.getCameraPosition();
Vector3 local_camera_position = worldToLocal(world_camera_position);
Vector3 local_reference_point = m_reference.nearestPoint(local_camera_position);
if(m_use_world_units) {
Vector3 world_reference_point = localToWorld(local_reference_point);
sqr_distance = (world_camera_position - world_reference_point).sqrMagnitude() * (lod_bias * lod_bias);
sqr_prestream_distance = getContext().KRENGINE_PRESTREAM_DISTANCE * getContext().KRENGINE_PRESTREAM_DISTANCE;
} else {
sqr_distance = (local_camera_position - local_reference_point).sqrMagnitude() * (lod_bias * lod_bias);
Vector3 world_reference_point = localToWorld(local_reference_point);
sqr_prestream_distance = worldToLocal(Vector3::Normalize(world_reference_point - world_camera_position) * getContext().KRENGINE_PRESTREAM_DISTANCE).sqrMagnitude(); // TODO, FINDME - Optimize with precalc?
}
float sqr_min_visible_distance = m_min_distance * m_min_distance;
float sqr_max_visible_distance = m_max_distance * m_max_distance;
if((sqr_distance >= sqr_min_visible_distance || m_min_distance == 0) && (sqr_distance < sqr_max_visible_distance || m_max_distance == 0)) {
return LOD_VISIBILITY_VISIBLE;
} else if((sqr_distance >= sqr_min_visible_distance - sqr_prestream_distance || m_min_distance == 0) && (sqr_distance < sqr_max_visible_distance + sqr_prestream_distance || m_max_distance == 0)) {
return LOD_VISIBILITY_PRESTREAM;
} else {
return LOD_VISIBILITY_HIDDEN;
}
}
}
float KRLODGroup::getMinDistance()
{
return m_min_distance;
}
float KRLODGroup::getMaxDistance()
{
return m_max_distance;
}
void KRLODGroup::setMinDistance(float min_distance)
{
m_min_distance = min_distance;
}
void KRLODGroup::setMaxDistance(float max_distance)
{
m_max_distance = max_distance;
}
void KRLODGroup::setUseWorldUnits(bool use_world_units)
{
m_use_world_units = use_world_units;
}
bool KRLODGroup::getUseWorldUnits() const
{
return m_use_world_units;
}

View File

@@ -1,485 +1,485 @@
//
// KRLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRLight.h"
#include "KRNode.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRShaderManager.h"
#include "KRShader.h"
#include "KRStockGeometry.h"
#include "KRDirectionalLight.h"
#include "KRSpotLight.h"
#include "KRPointLight.h"
KRLight::KRLight(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_intensity = 1.0f;
m_dust_particle_intensity = 1.0f;
m_color = Vector3::One();
m_flareTexture = "";
m_pFlareTexture = NULL;
m_flareSize = 0.0;
m_flareOcclusionSize = 0.05;
m_casts_shadow = true;
m_light_shafts = true;
m_dust_particle_density = 0.1f;
m_dust_particle_size = 1.0f;
m_occlusionQuery = 0;
// Initialize shadow buffers
m_cShadowBuffers = 0;
for(int iBuffer=0; iBuffer < KRENGINE_MAX_SHADOW_BUFFERS; iBuffer++) {
shadowFramebuffer[iBuffer] = 0;
shadowDepthTexture[iBuffer] = 0;
shadowValid[iBuffer] = false;
}
}
KRLight::~KRLight()
{
if(m_occlusionQuery) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
m_occlusionQuery = 0;
}
allocateShadowBuffers(0);
}
tinyxml2::XMLElement *KRLight::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("intensity", m_intensity);
e->SetAttribute("color_r", m_color.x);
e->SetAttribute("color_g", m_color.y);
e->SetAttribute("color_b", m_color.z);
e->SetAttribute("decay_start", m_decayStart);
e->SetAttribute("flare_size", m_flareSize);
e->SetAttribute("flare_occlusion_size", m_flareOcclusionSize);
e->SetAttribute("flare_texture", m_flareTexture.c_str());
e->SetAttribute("casts_shadow", m_casts_shadow ? "true" : "false");
e->SetAttribute("light_shafts", m_light_shafts ? "true" : "false");
e->SetAttribute("dust_particle_density", m_dust_particle_density);
e->SetAttribute("dust_particle_size", m_dust_particle_size);
e->SetAttribute("dust_particle_intensity", m_dust_particle_intensity);
return e;
}
void KRLight::loadXML(tinyxml2::XMLElement *e) {
KRNode::loadXML(e);
float x=1.0f,y=1.0f,z=1.0f;
if(e->QueryFloatAttribute("color_r", &x) != tinyxml2::XML_SUCCESS) {
x = 1.0;
}
if(e->QueryFloatAttribute("color_g", &y) != tinyxml2::XML_SUCCESS) {
y = 1.0;
}
if(e->QueryFloatAttribute("color_b", &z) != tinyxml2::XML_SUCCESS) {
z = 1.0;
}
m_color = Vector3(x,y,z);
if(e->QueryFloatAttribute("intensity", &m_intensity) != tinyxml2::XML_SUCCESS) {
m_intensity = 100.0;
}
if(e->QueryFloatAttribute("decay_start", &m_decayStart) != tinyxml2::XML_SUCCESS) {
m_decayStart = 0.0;
}
if(e->QueryFloatAttribute("flare_size", &m_flareSize) != tinyxml2::XML_SUCCESS) {
m_flareSize = 0.0;
}
if(e->QueryFloatAttribute("flare_occlusion_size", &m_flareOcclusionSize) != tinyxml2::XML_SUCCESS) {
m_flareOcclusionSize = 0.05;
}
if(e->QueryBoolAttribute("casts_shadow", &m_casts_shadow) != tinyxml2::XML_SUCCESS) {
m_casts_shadow = true;
}
if(e->QueryBoolAttribute("light_shafts", &m_light_shafts) != tinyxml2::XML_SUCCESS) {
m_light_shafts = true;
}
m_dust_particle_density = 0.1f;
if(e->QueryFloatAttribute("dust_particle_density", &m_dust_particle_density) != tinyxml2::XML_SUCCESS) {
m_dust_particle_density = 0.1f;
}
m_dust_particle_size = 1.0f;
if(e->QueryFloatAttribute("dust_particle_size", &m_dust_particle_size) != tinyxml2::XML_SUCCESS) {
m_dust_particle_size = 1.0f;
}
m_dust_particle_intensity = 1.0f;
if(e->QueryFloatAttribute("dust_particle_intensity", &m_dust_particle_intensity) != tinyxml2::XML_SUCCESS) {
m_dust_particle_intensity = 1.0f;
}
const char *szFlareTexture = e->Attribute("flare_texture");
if(szFlareTexture) {
m_flareTexture = szFlareTexture;
} else {
m_flareTexture = "";
}
m_pFlareTexture = NULL;
}
void KRLight::setFlareTexture(std::string flare_texture) {
m_flareTexture = flare_texture;
m_pFlareTexture = NULL;
}
void KRLight::setFlareSize(float flare_size) {
m_flareSize = flare_size;
}
void KRLight::setFlareOcclusionSize(float occlusion_size) {
m_flareOcclusionSize = occlusion_size;
}
void KRLight::setIntensity(float intensity) {
m_intensity = intensity;
}
float KRLight::getIntensity() {
return m_intensity;
}
const Vector3 &KRLight::getColor() {
return m_color;
}
void KRLight::setColor(const Vector3 &color) {
m_color = color;
}
void KRLight::setDecayStart(float decayStart) {
m_decayStart = decayStart;
}
float KRLight::getDecayStart() {
return m_decayStart;
}
void KRLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_GENERATE_SHADOWMAPS && (pCamera->settings.volumetric_environment_enable || pCamera->settings.dust_particle_enable || (pCamera->settings.m_cShadowBuffers > 0 && m_casts_shadow))) {
allocateShadowBuffers(configureShadowBufferViewports(viewport));
renderShadowBuffers(pCamera);
}
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES && pCamera->settings.dust_particle_enable) {
// Render brownian particles for dust floating in air
if(m_cShadowBuffers >= 1 && shadowValid[0] && m_dust_particle_density > 0.0f && m_dust_particle_size > 0.0f && m_dust_particle_intensity > 0.0f) {
if(viewport.visible(getBounds()) || true) { // FINDME, HACK need to remove "|| true"?
float particle_range = 600.0f;
int particle_count = m_dust_particle_density * pow(particle_range, 3);
if(particle_count > KRMeshManager::KRENGINE_MAX_RANDOM_PARTICLES) particle_count = KRMeshManager::KRENGINE_MAX_RANDOM_PARTICLES;
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthRangef(0.0, 1.0));
Matrix4 particleModelMatrix;
particleModelMatrix.scale(particle_range); // Scale the box symetrically to ensure that we don't have an uneven distribution of particles for different angles of the view frustrum
particleModelMatrix.translate(viewport.getCameraPosition());
std::vector<KRDirectionalLight *> this_directional_light;
std::vector<KRSpotLight *> this_spot_light;
std::vector<KRPointLight *> this_point_light;
KRDirectionalLight *directional_light = dynamic_cast<KRDirectionalLight *>(this);
KRSpotLight *spot_light = dynamic_cast<KRSpotLight *>(this);
KRPointLight *point_light = dynamic_cast<KRPointLight *>(this);
if(directional_light) {
this_directional_light.push_back(directional_light);
}
if(spot_light) {
this_spot_light.push_back(spot_light);
}
if(point_light) {
this_point_light.push_back(point_light);
}
KRShader *pParticleShader = m_pContext->getShaderManager()->getShader("dust_particle", pCamera, this_point_light, this_directional_light, this_spot_light, 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass);
if(getContext().getShaderManager()->selectShader(*pCamera, pParticleShader, viewport, particleModelMatrix, this_point_light, this_directional_light, this_spot_light, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color * pCamera->settings.dust_particle_intensity * m_dust_particle_intensity * m_intensity);
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_PARTICLE_ORIGIN, Matrix4::DotWDiv(Matrix4::Invert(particleModelMatrix), Vector3::Zero()));
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_dust_particle_size);
KRDataBlock particle_index_data;
m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), particle_index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, particle_count*3));
}
}
}
}
if(renderPass == KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE && pCamera->settings.volumetric_environment_enable && m_light_shafts) {
std::string shader_name = pCamera->settings.volumetric_environment_downsample != 0 ? "volumetric_fog_downsampled" : "volumetric_fog";
std::vector<KRDirectionalLight *> this_directional_light;
std::vector<KRSpotLight *> this_spot_light;
std::vector<KRPointLight *> this_point_light;
KRDirectionalLight *directional_light = dynamic_cast<KRDirectionalLight *>(this);
KRSpotLight *spot_light = dynamic_cast<KRSpotLight *>(this);
KRPointLight *point_light = dynamic_cast<KRPointLight *>(this);
if(directional_light) {
this_directional_light.push_back(directional_light);
}
if(spot_light) {
this_spot_light.push_back(spot_light);
}
if(point_light) {
this_point_light.push_back(point_light);
}
KRShader *pFogShader = m_pContext->getShaderManager()->getShader(shader_name, pCamera, this_point_light, this_directional_light, this_spot_light, 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_ADDITIVE_PARTICLES);
if(getContext().getShaderManager()->selectShader(*pCamera, pFogShader, viewport, Matrix4(), this_point_light, this_directional_light, this_spot_light, 0, KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE, Vector3::Zero(), 0.0f, Vector4::Zero())) {
int slice_count = (int)(pCamera->settings.volumetric_environment_quality * 495.0) + 5;
float slice_near = -pCamera->settings.getPerspectiveNearZ();
float slice_far = -pCamera->settings.volumetric_environment_max_distance;
float slice_spacing = (slice_far - slice_near) / slice_count;
pFogShader->setUniform(KRShader::KRENGINE_UNIFORM_SLICE_DEPTH_SCALE, Vector2(slice_near, slice_spacing));
pFogShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, (m_color * pCamera->settings.volumetric_environment_intensity * m_intensity * -slice_spacing / 1000.0f));
KRDataBlock index_data;
m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getVolumetricLightingVertexes(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), true, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, slice_count*6));
}
}
if(renderPass == KRNode::RENDER_PASS_PARTICLE_OCCLUSION) {
if(m_flareTexture.size() && m_flareSize > 0.0f) {
Matrix4 occlusion_test_sphere_matrix = Matrix4();
occlusion_test_sphere_matrix.scale(m_localScale * m_flareOcclusionSize);
occlusion_test_sphere_matrix.translate(m_localTranslation);
if(m_parentNode) {
occlusion_test_sphere_matrix *= m_parentNode->getModelMatrix();
}
if(getContext().getShaderManager()->selectShader("occlusion_test", *pCamera, point_lights, directional_lights, spot_lights, 0, viewport, occlusion_test_sphere_matrix, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery));
#if TARGET_OS_IPHONE
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery));
#else
GLDEBUG(glBeginQuery(GL_SAMPLES_PASSED, m_occlusionQuery));
#endif
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "occlusion_test", 1.0f);
}
}
#if TARGET_OS_IPHONE
GLDEBUG(glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT));
#else
GLDEBUG(glEndQuery(GL_SAMPLES_PASSED));
#endif
}
}
}
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES) {
if(m_flareTexture.size() && m_flareSize > 0.0f) {
if(m_occlusionQuery) {
GLuint params = 0;
GLDEBUG(glGetQueryObjectuivEXT(m_occlusionQuery, GL_QUERY_RESULT_EXT, &params));
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
if(params) {
if(!m_pFlareTexture && m_flareTexture.size()) {
m_pFlareTexture = getContext().getTextureManager()->getTexture(m_flareTexture);
}
if(m_pFlareTexture) {
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Render light flare on transparency pass
KRShader *pShader = getContext().getShaderManager()->getShader("flare", 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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, 1.0f);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_flareSize);
m_pContext->getTextureManager()->selectTexture(0, m_pFlareTexture, 0.0f, KRTexture::TEXTURE_USAGE_LIGHT_FLARE);
m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
}
}
}
}
void KRLight::allocateShadowBuffers(int cBuffers) {
// First deallocate buffers no longer needed
for(int iShadow = cBuffers; iShadow < KRENGINE_MAX_SHADOW_BUFFERS; iShadow++) {
if (shadowDepthTexture[iShadow]) {
GLDEBUG(glDeleteTextures(1, shadowDepthTexture + iShadow));
shadowDepthTexture[iShadow] = 0;
}
if (shadowFramebuffer[iShadow]) {
GLDEBUG(glDeleteFramebuffers(1, shadowFramebuffer + iShadow));
shadowFramebuffer[iShadow] = 0;
}
}
// Allocate newly required buffers
for(int iShadow = 0; iShadow < cBuffers; iShadow++) {
Vector2 viewportSize = m_shadowViewports[iShadow].getSize();
if(!shadowDepthTexture[iShadow]) {
shadowValid[iShadow] = false;
GLDEBUG(glGenFramebuffers(1, shadowFramebuffer + iShadow));
GLDEBUG(glGenTextures(1, shadowDepthTexture + iShadow));
// ===== Create offscreen shadow framebuffer object =====
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
// ----- Create Depth Texture for shadowFramebuffer -----
GLDEBUG( glBindTexture(GL_TEXTURE_2D, shadowDepthTexture[iShadow]));
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
m_pContext->getTextureManager()->_setWrapModeS(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
m_pContext->getTextureManager()->_setWrapModeT(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
#if GL_EXT_shadow_samplers
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_EXT, GL_COMPARE_REF_TO_TEXTURE_EXT)); // TODO - Detect GL_EXT_shadow_samplers and only activate if available
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_EXT, GL_LEQUAL)); // TODO - Detect GL_EXT_shadow_samplers and only activate if available
#endif
GLDEBUG(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewportSize.x, viewportSize.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
}
}
m_cShadowBuffers = cBuffers;
}
void KRLight::deleteBuffers()
{
// Called when this light wasn't used in the last frame, so we can free the resources for use by other lights
allocateShadowBuffers(0);
}
void KRLight::invalidateShadowBuffers()
{
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
shadowValid[iShadow] = false;
}
}
int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
{
return 0;
}
void KRLight::renderShadowBuffers(KRCamera *pCamera)
{
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
if(!shadowValid[iShadow]) {
shadowValid[iShadow] = true;
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
GLDEBUG(glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y));
GLDEBUG(glClearDepthf(0.0f));
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
GLDEBUG(glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2));
GLDEBUG(glClearDepthf(1.0f));
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
GLDEBUG(glDisable(GL_DITHER));
//GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts
//GLDEBUG(glEnable(GL_CULL_FACE));
GLDEBUG(glDisable(GL_CULL_FACE));
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LESS));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Disable alpha blending as we are using alpha channel for packed depth info
GLDEBUG(glDisable(GL_BLEND));
// Use shader program
KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector<KRPointLight *>(), std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], Matrix4(), std::vector<KRPointLight *>(), std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, KRNode::RENDER_PASS_SHADOWMAP, Vector3::Zero(), 0.0f, Vector4::Zero());
getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true);
GLDEBUG(glEnable(GL_CULL_FACE));
}
}
}
int KRLight::getShadowBufferCount()
{
int cBuffers=0;
for(int iBuffer=0; iBuffer < m_cShadowBuffers; iBuffer++) {
if(shadowValid[iBuffer]) {
cBuffers++;
} else {
break;
}
}
return cBuffers;
}
GLuint *KRLight::getShadowTextures()
{
return shadowDepthTexture;
}
KRViewport *KRLight::getShadowViewports()
{
return m_shadowViewports;
}
//
// KRLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRLight.h"
#include "KRNode.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRShaderManager.h"
#include "KRShader.h"
#include "KRStockGeometry.h"
#include "KRDirectionalLight.h"
#include "KRSpotLight.h"
#include "KRPointLight.h"
KRLight::KRLight(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_intensity = 1.0f;
m_dust_particle_intensity = 1.0f;
m_color = Vector3::One();
m_flareTexture = "";
m_pFlareTexture = NULL;
m_flareSize = 0.0f;
m_flareOcclusionSize = 0.05f;
m_casts_shadow = true;
m_light_shafts = true;
m_dust_particle_density = 0.1f;
m_dust_particle_size = 1.0f;
m_occlusionQuery = 0;
// Initialize shadow buffers
m_cShadowBuffers = 0;
for(int iBuffer=0; iBuffer < KRENGINE_MAX_SHADOW_BUFFERS; iBuffer++) {
shadowFramebuffer[iBuffer] = 0;
shadowDepthTexture[iBuffer] = 0;
shadowValid[iBuffer] = false;
}
}
KRLight::~KRLight()
{
if(m_occlusionQuery) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
m_occlusionQuery = 0;
}
allocateShadowBuffers(0);
}
tinyxml2::XMLElement *KRLight::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("intensity", m_intensity);
e->SetAttribute("color_r", m_color.x);
e->SetAttribute("color_g", m_color.y);
e->SetAttribute("color_b", m_color.z);
e->SetAttribute("decay_start", m_decayStart);
e->SetAttribute("flare_size", m_flareSize);
e->SetAttribute("flare_occlusion_size", m_flareOcclusionSize);
e->SetAttribute("flare_texture", m_flareTexture.c_str());
e->SetAttribute("casts_shadow", m_casts_shadow ? "true" : "false");
e->SetAttribute("light_shafts", m_light_shafts ? "true" : "false");
e->SetAttribute("dust_particle_density", m_dust_particle_density);
e->SetAttribute("dust_particle_size", m_dust_particle_size);
e->SetAttribute("dust_particle_intensity", m_dust_particle_intensity);
return e;
}
void KRLight::loadXML(tinyxml2::XMLElement *e) {
KRNode::loadXML(e);
float x=1.0f,y=1.0f,z=1.0f;
if(e->QueryFloatAttribute("color_r", &x) != tinyxml2::XML_SUCCESS) {
x = 1.0;
}
if(e->QueryFloatAttribute("color_g", &y) != tinyxml2::XML_SUCCESS) {
y = 1.0;
}
if(e->QueryFloatAttribute("color_b", &z) != tinyxml2::XML_SUCCESS) {
z = 1.0;
}
m_color = Vector3::Create(x,y,z);
if(e->QueryFloatAttribute("intensity", &m_intensity) != tinyxml2::XML_SUCCESS) {
m_intensity = 100.0;
}
if(e->QueryFloatAttribute("decay_start", &m_decayStart) != tinyxml2::XML_SUCCESS) {
m_decayStart = 0.0;
}
if(e->QueryFloatAttribute("flare_size", &m_flareSize) != tinyxml2::XML_SUCCESS) {
m_flareSize = 0.0;
}
if(e->QueryFloatAttribute("flare_occlusion_size", &m_flareOcclusionSize) != tinyxml2::XML_SUCCESS) {
m_flareOcclusionSize = 0.05f;
}
if(e->QueryBoolAttribute("casts_shadow", &m_casts_shadow) != tinyxml2::XML_SUCCESS) {
m_casts_shadow = true;
}
if(e->QueryBoolAttribute("light_shafts", &m_light_shafts) != tinyxml2::XML_SUCCESS) {
m_light_shafts = true;
}
m_dust_particle_density = 0.1f;
if(e->QueryFloatAttribute("dust_particle_density", &m_dust_particle_density) != tinyxml2::XML_SUCCESS) {
m_dust_particle_density = 0.1f;
}
m_dust_particle_size = 1.0f;
if(e->QueryFloatAttribute("dust_particle_size", &m_dust_particle_size) != tinyxml2::XML_SUCCESS) {
m_dust_particle_size = 1.0f;
}
m_dust_particle_intensity = 1.0f;
if(e->QueryFloatAttribute("dust_particle_intensity", &m_dust_particle_intensity) != tinyxml2::XML_SUCCESS) {
m_dust_particle_intensity = 1.0f;
}
const char *szFlareTexture = e->Attribute("flare_texture");
if(szFlareTexture) {
m_flareTexture = szFlareTexture;
} else {
m_flareTexture = "";
}
m_pFlareTexture = NULL;
}
void KRLight::setFlareTexture(std::string flare_texture) {
m_flareTexture = flare_texture;
m_pFlareTexture = NULL;
}
void KRLight::setFlareSize(float flare_size) {
m_flareSize = flare_size;
}
void KRLight::setFlareOcclusionSize(float occlusion_size) {
m_flareOcclusionSize = occlusion_size;
}
void KRLight::setIntensity(float intensity) {
m_intensity = intensity;
}
float KRLight::getIntensity() {
return m_intensity;
}
const Vector3 &KRLight::getColor() {
return m_color;
}
void KRLight::setColor(const Vector3 &color) {
m_color = color;
}
void KRLight::setDecayStart(float decayStart) {
m_decayStart = decayStart;
}
float KRLight::getDecayStart() {
return m_decayStart;
}
void KRLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_GENERATE_SHADOWMAPS && (pCamera->settings.volumetric_environment_enable || pCamera->settings.dust_particle_enable || (pCamera->settings.m_cShadowBuffers > 0 && m_casts_shadow))) {
allocateShadowBuffers(configureShadowBufferViewports(viewport));
renderShadowBuffers(pCamera);
}
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES && pCamera->settings.dust_particle_enable) {
// Render brownian particles for dust floating in air
if(m_cShadowBuffers >= 1 && shadowValid[0] && m_dust_particle_density > 0.0f && m_dust_particle_size > 0.0f && m_dust_particle_intensity > 0.0f) {
if(viewport.visible(getBounds()) || true) { // FINDME, HACK need to remove "|| true"?
float particle_range = 600.0f;
int particle_count = m_dust_particle_density * pow(particle_range, 3);
if(particle_count > KRMeshManager::KRENGINE_MAX_RANDOM_PARTICLES) particle_count = KRMeshManager::KRENGINE_MAX_RANDOM_PARTICLES;
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthRangef(0.0, 1.0));
Matrix4 particleModelMatrix;
particleModelMatrix.scale(particle_range); // Scale the box symetrically to ensure that we don't have an uneven distribution of particles for different angles of the view frustrum
particleModelMatrix.translate(viewport.getCameraPosition());
std::vector<KRDirectionalLight *> this_directional_light;
std::vector<KRSpotLight *> this_spot_light;
std::vector<KRPointLight *> this_point_light;
KRDirectionalLight *directional_light = dynamic_cast<KRDirectionalLight *>(this);
KRSpotLight *spot_light = dynamic_cast<KRSpotLight *>(this);
KRPointLight *point_light = dynamic_cast<KRPointLight *>(this);
if(directional_light) {
this_directional_light.push_back(directional_light);
}
if(spot_light) {
this_spot_light.push_back(spot_light);
}
if(point_light) {
this_point_light.push_back(point_light);
}
KRShader *pParticleShader = m_pContext->getShaderManager()->getShader("dust_particle", pCamera, this_point_light, this_directional_light, this_spot_light, 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass);
if(getContext().getShaderManager()->selectShader(*pCamera, pParticleShader, viewport, particleModelMatrix, this_point_light, this_directional_light, this_spot_light, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color * pCamera->settings.dust_particle_intensity * m_dust_particle_intensity * m_intensity);
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_PARTICLE_ORIGIN, Matrix4::DotWDiv(Matrix4::Invert(particleModelMatrix), Vector3::Zero()));
pParticleShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_dust_particle_size);
KRDataBlock particle_index_data;
m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getRandomParticles(), particle_index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), true, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, particle_count*3));
}
}
}
}
if(renderPass == KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE && pCamera->settings.volumetric_environment_enable && m_light_shafts) {
std::string shader_name = pCamera->settings.volumetric_environment_downsample != 0 ? "volumetric_fog_downsampled" : "volumetric_fog";
std::vector<KRDirectionalLight *> this_directional_light;
std::vector<KRSpotLight *> this_spot_light;
std::vector<KRPointLight *> this_point_light;
KRDirectionalLight *directional_light = dynamic_cast<KRDirectionalLight *>(this);
KRSpotLight *spot_light = dynamic_cast<KRSpotLight *>(this);
KRPointLight *point_light = dynamic_cast<KRPointLight *>(this);
if(directional_light) {
this_directional_light.push_back(directional_light);
}
if(spot_light) {
this_spot_light.push_back(spot_light);
}
if(point_light) {
this_point_light.push_back(point_light);
}
KRShader *pFogShader = m_pContext->getShaderManager()->getShader(shader_name, pCamera, this_point_light, this_directional_light, this_spot_light, 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_ADDITIVE_PARTICLES);
if(getContext().getShaderManager()->selectShader(*pCamera, pFogShader, viewport, Matrix4(), this_point_light, this_directional_light, this_spot_light, 0, KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE, Vector3::Zero(), 0.0f, Vector4::Zero())) {
int slice_count = (int)(pCamera->settings.volumetric_environment_quality * 495.0) + 5;
float slice_near = -pCamera->settings.getPerspectiveNearZ();
float slice_far = -pCamera->settings.volumetric_environment_max_distance;
float slice_spacing = (slice_far - slice_near) / slice_count;
pFogShader->setUniform(KRShader::KRENGINE_UNIFORM_SLICE_DEPTH_SCALE, Vector2::Create(slice_near, slice_spacing));
pFogShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, (m_color * pCamera->settings.volumetric_environment_intensity * m_intensity * -slice_spacing / 1000.0f));
KRDataBlock index_data;
m_pContext->getMeshManager()->bindVBO(m_pContext->getMeshManager()->getVolumetricLightingVertexes(), index_data, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), true, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, slice_count*6));
}
}
if(renderPass == KRNode::RENDER_PASS_PARTICLE_OCCLUSION) {
if(m_flareTexture.size() && m_flareSize > 0.0f) {
Matrix4 occlusion_test_sphere_matrix = Matrix4();
occlusion_test_sphere_matrix.scale(m_localScale * m_flareOcclusionSize);
occlusion_test_sphere_matrix.translate(m_localTranslation);
if(m_parentNode) {
occlusion_test_sphere_matrix *= m_parentNode->getModelMatrix();
}
if(getContext().getShaderManager()->selectShader("occlusion_test", *pCamera, point_lights, directional_lights, spot_lights, 0, viewport, occlusion_test_sphere_matrix, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery));
#if TARGET_OS_IPHONE
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery));
#else
GLDEBUG(glBeginQuery(GL_SAMPLES_PASSED, m_occlusionQuery));
#endif
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "occlusion_test", 1.0f);
}
}
#if TARGET_OS_IPHONE
GLDEBUG(glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT));
#else
GLDEBUG(glEndQuery(GL_SAMPLES_PASSED));
#endif
}
}
}
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES) {
if(m_flareTexture.size() && m_flareSize > 0.0f) {
if(m_occlusionQuery) {
GLuint params = 0;
GLDEBUG(glGetQueryObjectuivEXT(m_occlusionQuery, GL_QUERY_RESULT_EXT, &params));
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
if(params) {
if(!m_pFlareTexture && m_flareTexture.size()) {
m_pFlareTexture = getContext().getTextureManager()->getTexture(m_flareTexture);
}
if(m_pFlareTexture) {
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Render light flare on transparency pass
KRShader *pShader = getContext().getShaderManager()->getShader("flare", 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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, 1.0f);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_FLARE_SIZE, m_flareSize);
m_pContext->getTextureManager()->selectTexture(0, m_pFlareTexture, 0.0f, KRTexture::TEXTURE_USAGE_LIGHT_FLARE);
m_pContext->getMeshManager()->bindVBO(&getContext().getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
}
}
}
}
void KRLight::allocateShadowBuffers(int cBuffers) {
// First deallocate buffers no longer needed
for(int iShadow = cBuffers; iShadow < KRENGINE_MAX_SHADOW_BUFFERS; iShadow++) {
if (shadowDepthTexture[iShadow]) {
GLDEBUG(glDeleteTextures(1, shadowDepthTexture + iShadow));
shadowDepthTexture[iShadow] = 0;
}
if (shadowFramebuffer[iShadow]) {
GLDEBUG(glDeleteFramebuffers(1, shadowFramebuffer + iShadow));
shadowFramebuffer[iShadow] = 0;
}
}
// Allocate newly required buffers
for(int iShadow = 0; iShadow < cBuffers; iShadow++) {
Vector2 viewportSize = m_shadowViewports[iShadow].getSize();
if(!shadowDepthTexture[iShadow]) {
shadowValid[iShadow] = false;
GLDEBUG(glGenFramebuffers(1, shadowFramebuffer + iShadow));
GLDEBUG(glGenTextures(1, shadowDepthTexture + iShadow));
// ===== Create offscreen shadow framebuffer object =====
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
// ----- Create Depth Texture for shadowFramebuffer -----
GLDEBUG( glBindTexture(GL_TEXTURE_2D, shadowDepthTexture[iShadow]));
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
m_pContext->getTextureManager()->_setWrapModeS(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
m_pContext->getTextureManager()->_setWrapModeT(shadowDepthTexture[iShadow], GL_CLAMP_TO_EDGE);
#if GL_EXT_shadow_samplers
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_EXT, GL_COMPARE_REF_TO_TEXTURE_EXT)); // TODO - Detect GL_EXT_shadow_samplers and only activate if available
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_EXT, GL_LEQUAL)); // TODO - Detect GL_EXT_shadow_samplers and only activate if available
#endif
GLDEBUG(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewportSize.x, viewportSize.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
}
}
m_cShadowBuffers = cBuffers;
}
void KRLight::deleteBuffers()
{
// Called when this light wasn't used in the last frame, so we can free the resources for use by other lights
allocateShadowBuffers(0);
}
void KRLight::invalidateShadowBuffers()
{
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
shadowValid[iShadow] = false;
}
}
int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
{
return 0;
}
void KRLight::renderShadowBuffers(KRCamera *pCamera)
{
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
if(!shadowValid[iShadow]) {
shadowValid[iShadow] = true;
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
GLDEBUG(glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y));
GLDEBUG(glClearDepthf(0.0f));
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
GLDEBUG(glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2));
GLDEBUG(glClearDepthf(1.0f));
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
GLDEBUG(glDisable(GL_DITHER));
//GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts
//GLDEBUG(glEnable(GL_CULL_FACE));
GLDEBUG(glDisable(GL_CULL_FACE));
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LESS));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Disable alpha blending as we are using alpha channel for packed depth info
GLDEBUG(glDisable(GL_BLEND));
// Use shader program
KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector<KRPointLight *>(), std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], Matrix4(), std::vector<KRPointLight *>(), std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, KRNode::RENDER_PASS_SHADOWMAP, Vector3::Zero(), 0.0f, Vector4::Zero());
getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true);
GLDEBUG(glEnable(GL_CULL_FACE));
}
}
}
int KRLight::getShadowBufferCount()
{
int cBuffers=0;
for(int iBuffer=0; iBuffer < m_cShadowBuffers; iBuffer++) {
if(shadowValid[iBuffer]) {
cBuffers++;
} else {
break;
}
}
return cBuffers;
}
GLuint *KRLight::getShadowTextures()
{
return shadowDepthTexture;
}
KRViewport *KRLight::getShadowViewports()
{
return m_shadowViewports;
}

View File

@@ -1,422 +1,422 @@
//
// KRMaterial.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.
//
#include "KREngine-common.h"
#include "KRMaterial.h"
#include "KRTextureManager.h"
#include "KRContext.h"
KRMaterial::KRMaterial(KRContext &context, const char *szName) : KRResource(context, szName) {
m_name = szName;
m_pAmbientMap = NULL;
m_pDiffuseMap = NULL;
m_pSpecularMap = NULL;
m_pNormalMap = NULL;
m_pReflectionMap = NULL;
m_pReflectionCube = NULL;
m_ambientColor = Vector3::Zero();
m_diffuseColor = Vector3::One();
m_specularColor = Vector3::One();
m_reflectionColor = Vector3::Zero();
m_tr = (GLfloat)1.0f;
m_ns = (GLfloat)0.0f;
m_ambientMap = "";
m_diffuseMap = "";
m_specularMap = "";
m_normalMap = "";
m_reflectionMap = "";
m_reflectionCube = "";
m_ambientMapOffset = Vector2(0.0f, 0.0f);
m_specularMapOffset = Vector2(0.0f, 0.0f);
m_diffuseMapOffset = Vector2(0.0f, 0.0f);
m_ambientMapScale = Vector2(1.0f, 1.0f);
m_specularMapScale = Vector2(1.0f, 1.0f);
m_diffuseMapScale = Vector2(1.0f, 1.0f);
m_reflectionMapOffset = Vector2(0.0f, 0.0f);
m_reflectionMapScale = Vector2(1.0f, 1.0f);
m_alpha_mode = KRMATERIAL_ALPHA_MODE_OPAQUE;
}
KRMaterial::~KRMaterial() {
}
std::string KRMaterial::getExtension() {
return "mtl";
}
bool KRMaterial::needsVertexTangents()
{
return m_normalMap.size() > 0;
}
bool KRMaterial::save(KRDataBlock &data) {
std::stringstream stream;
stream.precision(std::numeric_limits<long double>::digits10);
stream.setf(std::ios::fixed,std::ios::floatfield);
stream << "newmtl " << m_name;
stream << "\nka " << m_ambientColor.x << " " << m_ambientColor.y << " " << m_ambientColor.z;
stream << "\nkd " << m_diffuseColor.x << " " << m_diffuseColor.y << " " << m_diffuseColor.z;
stream << "\nks " << m_specularColor.x << " " << m_specularColor.y << " " << m_specularColor.z;
stream << "\nkr " << m_reflectionColor.x << " " << m_reflectionColor.y << " " << m_reflectionColor.z;
stream << "\nTr " << m_tr;
stream << "\nNs " << m_ns;
if(m_ambientMap.size()) {
stream << "\nmap_Ka " << m_ambientMap << ".pvr -s " << m_ambientMapScale.x << " " << m_ambientMapScale.y << " -o " << m_ambientMapOffset.x << " " << m_ambientMapOffset.y;
} else {
stream << "\n# map_Ka filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_diffuseMap.size()) {
stream << "\nmap_Kd " << m_diffuseMap << ".pvr -s " << m_diffuseMapScale.x << " " << m_diffuseMapScale.y << " -o " << m_diffuseMapOffset.x << " " << m_diffuseMapOffset.y;
} else {
stream << "\n# map_Kd filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_specularMap.size()) {
stream << "\nmap_Ks " << m_specularMap << ".pvr -s " << m_specularMapScale.x << " " << m_specularMapScale.y << " -o " << m_specularMapOffset.x << " " << m_specularMapOffset.y << "\n";
} else {
stream << "\n# map_Ks filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_normalMap.size()) {
stream << "\nmap_Normal " << m_normalMap << ".pvr -s " << m_normalMapScale.x << " " << m_normalMapScale.y << " -o " << m_normalMapOffset.x << " " << m_normalMapOffset.y;
} else {
stream << "\n# map_Normal filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_reflectionMap.size()) {
stream << "\nmap_Reflection " << m_reflectionMap << ".pvr -s " << m_reflectionMapScale.x << " " << m_reflectionMapScale.y << " -o " << m_reflectionMapOffset.x << " " << m_reflectionMapOffset.y;
} else {
stream << "\n# map_Reflection filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_reflectionCube.size()) {
stream << "\nmap_ReflectionCube " << m_reflectionCube << ".pvr";
} else {
stream << "\n# map_ReflectionCube cubemapname";
}
switch(m_alpha_mode) {
case KRMATERIAL_ALPHA_MODE_OPAQUE:
stream << "\nalpha_mode opaque";
break;
case KRMATERIAL_ALPHA_MODE_TEST:
stream << "\nalpha_mode test";
break;
case KRMATERIAL_ALPHA_MODE_BLENDONESIDE:
stream << "\nalpha_mode blendoneside";
break;
case KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE:
stream << "\nalpha_mode blendtwoside";
break;
}
stream << "\n# alpha_mode opaque, test, blendoneside, or blendtwoside";
stream << "\n";
data.append(stream.str());
return true;
}
void KRMaterial::setAmbientMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_ambientMap = texture_name;
m_ambientMapScale = texture_scale;
m_ambientMapOffset = texture_offset;
}
void KRMaterial::setDiffuseMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_diffuseMap = texture_name;
m_diffuseMapScale = texture_scale;
m_diffuseMapOffset = texture_offset;
}
void KRMaterial::setSpecularMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_specularMap = texture_name;
m_specularMapScale = texture_scale;
m_specularMapOffset = texture_offset;
}
void KRMaterial::setNormalMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_normalMap = texture_name;
m_normalMapScale = texture_scale;
m_normalMapOffset = texture_offset;
}
void KRMaterial::setReflectionMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_reflectionMap = texture_name;
m_reflectionMapScale = texture_scale;
m_reflectionMapOffset = texture_offset;
}
void KRMaterial::setReflectionCube(std::string texture_name) {
m_reflectionCube = texture_name;
}
void KRMaterial::setAlphaMode(KRMaterial::alpha_mode_type alpha_mode) {
m_alpha_mode = alpha_mode;
}
KRMaterial::alpha_mode_type KRMaterial::getAlphaMode() {
return m_alpha_mode;
}
void KRMaterial::setAmbient(const Vector3 &c) {
m_ambientColor = c;
}
void KRMaterial::setDiffuse(const Vector3 &c) {
m_diffuseColor = c;
}
void KRMaterial::setSpecular(const Vector3 &c) {
m_specularColor = c;
}
void KRMaterial::setReflection(const Vector3 &c) {
m_reflectionColor = c;
}
void KRMaterial::setTransparency(GLfloat a) {
if(a < 1.0f && m_alpha_mode == KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE) {
setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE);
}
m_tr = a;
}
void KRMaterial::setShininess(GLfloat s) {
m_ns = s;
}
bool KRMaterial::isTransparent() {
return m_tr < 1.0 || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE;
}
void KRMaterial::preStream(float lodCoverage)
{
getTextures();
if(m_pAmbientMap) {
m_pAmbientMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_AMBIENT_MAP);
}
if(m_pDiffuseMap) {
m_pDiffuseMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP);
}
if(m_pNormalMap) {
m_pNormalMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP);
}
if(m_pSpecularMap) {
m_pSpecularMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP);
}
if(m_pReflectionMap) {
m_pReflectionMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP);
}
if(m_pReflectionCube) {
m_pReflectionCube->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE);
}
}
kraken_stream_level KRMaterial::getStreamLevel()
{
kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ;
getTextures();
if(m_pAmbientMap) {
stream_level = KRMIN(stream_level, m_pAmbientMap->getStreamLevel(KRTexture::TEXTURE_USAGE_AMBIENT_MAP));
}
if(m_pDiffuseMap) {
stream_level = KRMIN(stream_level, m_pDiffuseMap->getStreamLevel(KRTexture::TEXTURE_USAGE_DIFFUSE_MAP));
}
if(m_pNormalMap) {
stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(KRTexture::TEXTURE_USAGE_NORMAL_MAP));
}
if(m_pSpecularMap) {
stream_level = KRMIN(stream_level, m_pSpecularMap->getStreamLevel(KRTexture::TEXTURE_USAGE_SPECULAR_MAP));
}
if(m_pReflectionMap) {
stream_level = KRMIN(stream_level, m_pReflectionMap->getStreamLevel(KRTexture::TEXTURE_USAGE_REFLECTION_MAP));
}
if(m_pReflectionCube) {
stream_level = KRMIN(stream_level, m_pReflectionCube->getStreamLevel(KRTexture::TEXTURE_USAGE_REFECTION_CUBE));
}
return stream_level;
}
void KRMaterial::getTextures()
{
if(!m_pAmbientMap && m_ambientMap.size()) {
m_pAmbientMap = getContext().getTextureManager()->getTexture(m_ambientMap);
}
if(!m_pDiffuseMap && m_diffuseMap.size()) {
m_pDiffuseMap = getContext().getTextureManager()->getTexture(m_diffuseMap);
}
if(!m_pNormalMap && m_normalMap.size()) {
m_pNormalMap = getContext().getTextureManager()->getTexture(m_normalMap);
}
if(!m_pSpecularMap && m_specularMap.size()) {
m_pSpecularMap = getContext().getTextureManager()->getTexture(m_specularMap);
}
if(!m_pReflectionMap && m_reflectionMap.size()) {
m_pReflectionMap = getContext().getTextureManager()->getTexture(m_reflectionMap);
}
if(!m_pReflectionCube && m_reflectionCube.size()) {
m_pReflectionCube = getContext().getTextureManager()->getTextureCube(m_reflectionCube.c_str());
}
}
bool KRMaterial::bind(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const std::vector<KRBone *> &bones, const std::vector<Matrix4> &bind_poses, const KRViewport &viewport, const Matrix4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const Vector3 &rim_color, float rim_power, float lod_coverage) {
bool bLightMap = pLightMap && pCamera->settings.bEnableLightMap;
getTextures();
Vector2 default_scale = Vector2::One();
Vector2 default_offset = Vector2::Zero();
bool bHasReflection = m_reflectionColor != Vector3::Zero();
bool bDiffuseMap = m_pDiffuseMap != NULL && pCamera->settings.bEnableDiffuseMap;
bool bNormalMap = m_pNormalMap != NULL && pCamera->settings.bEnableNormalMap;
bool bSpecMap = m_pSpecularMap != NULL && pCamera->settings.bEnableSpecMap;
bool bReflectionMap = m_pReflectionMap != NULL && pCamera->settings.bEnableReflectionMap && pCamera->settings.bEnableReflection && bHasReflection;
bool bReflectionCubeMap = m_pReflectionCube != NULL && pCamera->settings.bEnableReflection && bHasReflection;
bool bAlphaTest = (m_alpha_mode == KRMATERIAL_ALPHA_MODE_TEST) && bDiffuseMap;
bool bAlphaBlend = (m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE) || (m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE);
KRShader *pShader = getContext().getShaderManager()->getShader("ObjectShader", pCamera, point_lights, directional_lights, spot_lights, bones.size(), bDiffuseMap, bNormalMap, bSpecMap, bReflectionMap, bReflectionCubeMap, bLightMap, m_diffuseMapScale != default_scale && bDiffuseMap, m_specularMapScale != default_scale && bSpecMap, m_normalMapScale != default_scale && bNormalMap, m_reflectionMapScale != default_scale && bReflectionMap, m_diffuseMapOffset != default_offset && bDiffuseMap, m_specularMapOffset != default_offset && bSpecMap, m_normalMapOffset != default_offset && bNormalMap, m_reflectionMapOffset != default_offset && bReflectionMap, bAlphaTest, bAlphaBlend, renderPass, rim_power != 0.0f);
Vector4 fade_color;
if(!getContext().getShaderManager()->selectShader(*pCamera, pShader, viewport, matModel, point_lights, directional_lights, spot_lights, 0, renderPass, rim_color, rim_power, fade_color)) {
return false;
}
// Bind bones
if(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS] != -1) {
GLfloat bone_mats[256 * 16];
GLfloat *bone_mat_component = bone_mats;
for(int bone_index=0; bone_index < bones.size(); bone_index++) {
KRBone *bone = bones[bone_index];
// Vector3 initialRotation = bone->getInitialLocalRotation();
// Vector3 rotation = bone->getLocalRotation();
// Vector3 initialTranslation = bone->getInitialLocalTranslation();
// Vector3 translation = bone->getLocalTranslation();
// Vector3 initialScale = bone->getInitialLocalScale();
// Vector3 scale = bone->getLocalScale();
//
//printf("%s - delta rotation: %.4f %.4f %.4f\n", bone->getName().c_str(), (rotation.x - initialRotation.x) * 180.0 / M_PI, (rotation.y - initialRotation.y) * 180.0 / M_PI, (rotation.z - initialRotation.z) * 180.0 / M_PI);
//printf("%s - delta translation: %.4f %.4f %.4f\n", bone->getName().c_str(), translation.x - initialTranslation.x, translation.y - initialTranslation.y, translation.z - initialTranslation.z);
// printf("%s - delta scale: %.4f %.4f %.4f\n", bone->getName().c_str(), scale.x - initialScale.x, scale.y - initialScale.y, scale.z - initialScale.z);
Matrix4 skin_bone_bind_pose = bind_poses[bone_index];
Matrix4 active_mat = bone->getActivePoseMatrix();
Matrix4 inv_bind_mat = bone->getInverseBindPoseMatrix();
Matrix4 inv_bind_mat2 = Matrix4::Invert(bind_poses[bone_index]);
Matrix4 t = (inv_bind_mat * active_mat);
Matrix4 t2 = inv_bind_mat2 * bone->getModelMatrix();
for(int i=0; i < 16; i++) {
*bone_mat_component++ = t[i];
}
}
if(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS] != -1) {
glUniformMatrix4fv(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS], bones.size(), GL_FALSE, bone_mats);
}
}
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_AMBIENT, m_ambientColor + pCamera->settings.ambient_intensity);
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE) {
// We pre-multiply the light color with the material color in the forward renderer
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_DIFFUSE, Vector3(m_diffuseColor.x * pCamera->settings.light_intensity.x, m_diffuseColor.y * pCamera->settings.light_intensity.y, m_diffuseColor.z * pCamera->settings.light_intensity.z));
} else {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_DIFFUSE, m_diffuseColor);
}
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE) {
// We pre-multiply the light color with the material color in the forward renderer
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SPECULAR, Vector3(m_specularColor.x * pCamera->settings.light_intensity.x, m_specularColor.y * pCamera->settings.light_intensity.y, m_specularColor.z * pCamera->settings.light_intensity.z));
} else {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SPECULAR, m_specularColor);
}
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SHININESS, m_ns);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_REFLECTION, m_reflectionColor);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_DIFFUSETEXTURE_SCALE, m_diffuseMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_SPECULARTEXTURE_SCALE, m_specularMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_REFLECTIONTEXTURE_SCALE, m_reflectionMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_NORMALTEXTURE_SCALE, m_normalMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_DIFFUSETEXTURE_OFFSET, m_diffuseMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_SPECULARTEXTURE_OFFSET, m_specularMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_REFLECTIONTEXTURE_OFFSET, m_reflectionMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_NORMALTEXTURE_OFFSET, m_normalMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_tr);
if(bDiffuseMap) {
m_pContext->getTextureManager()->selectTexture(0, m_pDiffuseMap, lod_coverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP);
}
if(bSpecMap) {
m_pContext->getTextureManager()->selectTexture(1, m_pSpecularMap, lod_coverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP);
}
if(bNormalMap) {
m_pContext->getTextureManager()->selectTexture(2, m_pNormalMap, lod_coverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP);
}
if(bReflectionCubeMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) {
m_pContext->getTextureManager()->selectTexture(4, m_pReflectionCube, lod_coverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE);
}
if(bReflectionMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) {
// GL_TEXTURE7 is used for reading the depth buffer in gBuffer pass 2 and re-used for the reflection map in gBuffer Pass 3 and in forward rendering
m_pContext->getTextureManager()->selectTexture(7, m_pReflectionMap, lod_coverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP);
}
return true;
}
const std::string &KRMaterial::getName() const
{
return m_name;
}
//
// KRMaterial.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.
//
#include "KREngine-common.h"
#include "KRMaterial.h"
#include "KRTextureManager.h"
#include "KRContext.h"
KRMaterial::KRMaterial(KRContext &context, const char *szName) : KRResource(context, szName) {
m_name = szName;
m_pAmbientMap = NULL;
m_pDiffuseMap = NULL;
m_pSpecularMap = NULL;
m_pNormalMap = NULL;
m_pReflectionMap = NULL;
m_pReflectionCube = NULL;
m_ambientColor = Vector3::Zero();
m_diffuseColor = Vector3::One();
m_specularColor = Vector3::One();
m_reflectionColor = Vector3::Zero();
m_tr = (GLfloat)1.0f;
m_ns = (GLfloat)0.0f;
m_ambientMap = "";
m_diffuseMap = "";
m_specularMap = "";
m_normalMap = "";
m_reflectionMap = "";
m_reflectionCube = "";
m_ambientMapOffset = Vector2::Create(0.0f, 0.0f);
m_specularMapOffset = Vector2::Create(0.0f, 0.0f);
m_diffuseMapOffset = Vector2::Create(0.0f, 0.0f);
m_ambientMapScale = Vector2::Create(1.0f, 1.0f);
m_specularMapScale = Vector2::Create(1.0f, 1.0f);
m_diffuseMapScale = Vector2::Create(1.0f, 1.0f);
m_reflectionMapOffset = Vector2::Create(0.0f, 0.0f);
m_reflectionMapScale = Vector2::Create(1.0f, 1.0f);
m_alpha_mode = KRMATERIAL_ALPHA_MODE_OPAQUE;
}
KRMaterial::~KRMaterial() {
}
std::string KRMaterial::getExtension() {
return "mtl";
}
bool KRMaterial::needsVertexTangents()
{
return m_normalMap.size() > 0;
}
bool KRMaterial::save(KRDataBlock &data) {
std::stringstream stream;
stream.precision(std::numeric_limits<long double>::digits10);
stream.setf(std::ios::fixed,std::ios::floatfield);
stream << "newmtl " << m_name;
stream << "\nka " << m_ambientColor.x << " " << m_ambientColor.y << " " << m_ambientColor.z;
stream << "\nkd " << m_diffuseColor.x << " " << m_diffuseColor.y << " " << m_diffuseColor.z;
stream << "\nks " << m_specularColor.x << " " << m_specularColor.y << " " << m_specularColor.z;
stream << "\nkr " << m_reflectionColor.x << " " << m_reflectionColor.y << " " << m_reflectionColor.z;
stream << "\nTr " << m_tr;
stream << "\nNs " << m_ns;
if(m_ambientMap.size()) {
stream << "\nmap_Ka " << m_ambientMap << ".pvr -s " << m_ambientMapScale.x << " " << m_ambientMapScale.y << " -o " << m_ambientMapOffset.x << " " << m_ambientMapOffset.y;
} else {
stream << "\n# map_Ka filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_diffuseMap.size()) {
stream << "\nmap_Kd " << m_diffuseMap << ".pvr -s " << m_diffuseMapScale.x << " " << m_diffuseMapScale.y << " -o " << m_diffuseMapOffset.x << " " << m_diffuseMapOffset.y;
} else {
stream << "\n# map_Kd filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_specularMap.size()) {
stream << "\nmap_Ks " << m_specularMap << ".pvr -s " << m_specularMapScale.x << " " << m_specularMapScale.y << " -o " << m_specularMapOffset.x << " " << m_specularMapOffset.y << "\n";
} else {
stream << "\n# map_Ks filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_normalMap.size()) {
stream << "\nmap_Normal " << m_normalMap << ".pvr -s " << m_normalMapScale.x << " " << m_normalMapScale.y << " -o " << m_normalMapOffset.x << " " << m_normalMapOffset.y;
} else {
stream << "\n# map_Normal filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_reflectionMap.size()) {
stream << "\nmap_Reflection " << m_reflectionMap << ".pvr -s " << m_reflectionMapScale.x << " " << m_reflectionMapScale.y << " -o " << m_reflectionMapOffset.x << " " << m_reflectionMapOffset.y;
} else {
stream << "\n# map_Reflection filename.pvr -s 1.0 1.0 -o 0.0 0.0";
}
if(m_reflectionCube.size()) {
stream << "\nmap_ReflectionCube " << m_reflectionCube << ".pvr";
} else {
stream << "\n# map_ReflectionCube cubemapname";
}
switch(m_alpha_mode) {
case KRMATERIAL_ALPHA_MODE_OPAQUE:
stream << "\nalpha_mode opaque";
break;
case KRMATERIAL_ALPHA_MODE_TEST:
stream << "\nalpha_mode test";
break;
case KRMATERIAL_ALPHA_MODE_BLENDONESIDE:
stream << "\nalpha_mode blendoneside";
break;
case KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE:
stream << "\nalpha_mode blendtwoside";
break;
}
stream << "\n# alpha_mode opaque, test, blendoneside, or blendtwoside";
stream << "\n";
data.append(stream.str());
return true;
}
void KRMaterial::setAmbientMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_ambientMap = texture_name;
m_ambientMapScale = texture_scale;
m_ambientMapOffset = texture_offset;
}
void KRMaterial::setDiffuseMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_diffuseMap = texture_name;
m_diffuseMapScale = texture_scale;
m_diffuseMapOffset = texture_offset;
}
void KRMaterial::setSpecularMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_specularMap = texture_name;
m_specularMapScale = texture_scale;
m_specularMapOffset = texture_offset;
}
void KRMaterial::setNormalMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_normalMap = texture_name;
m_normalMapScale = texture_scale;
m_normalMapOffset = texture_offset;
}
void KRMaterial::setReflectionMap(std::string texture_name, Vector2 texture_scale, Vector2 texture_offset) {
m_reflectionMap = texture_name;
m_reflectionMapScale = texture_scale;
m_reflectionMapOffset = texture_offset;
}
void KRMaterial::setReflectionCube(std::string texture_name) {
m_reflectionCube = texture_name;
}
void KRMaterial::setAlphaMode(KRMaterial::alpha_mode_type alpha_mode) {
m_alpha_mode = alpha_mode;
}
KRMaterial::alpha_mode_type KRMaterial::getAlphaMode() {
return m_alpha_mode;
}
void KRMaterial::setAmbient(const Vector3 &c) {
m_ambientColor = c;
}
void KRMaterial::setDiffuse(const Vector3 &c) {
m_diffuseColor = c;
}
void KRMaterial::setSpecular(const Vector3 &c) {
m_specularColor = c;
}
void KRMaterial::setReflection(const Vector3 &c) {
m_reflectionColor = c;
}
void KRMaterial::setTransparency(GLfloat a) {
if(a < 1.0f && m_alpha_mode == KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE) {
setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE);
}
m_tr = a;
}
void KRMaterial::setShininess(GLfloat s) {
m_ns = s;
}
bool KRMaterial::isTransparent() {
return m_tr < 1.0 || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE || m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE;
}
void KRMaterial::preStream(float lodCoverage)
{
getTextures();
if(m_pAmbientMap) {
m_pAmbientMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_AMBIENT_MAP);
}
if(m_pDiffuseMap) {
m_pDiffuseMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP);
}
if(m_pNormalMap) {
m_pNormalMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP);
}
if(m_pSpecularMap) {
m_pSpecularMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP);
}
if(m_pReflectionMap) {
m_pReflectionMap->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP);
}
if(m_pReflectionCube) {
m_pReflectionCube->resetPoolExpiry(lodCoverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE);
}
}
kraken_stream_level KRMaterial::getStreamLevel()
{
kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ;
getTextures();
if(m_pAmbientMap) {
stream_level = KRMIN(stream_level, m_pAmbientMap->getStreamLevel(KRTexture::TEXTURE_USAGE_AMBIENT_MAP));
}
if(m_pDiffuseMap) {
stream_level = KRMIN(stream_level, m_pDiffuseMap->getStreamLevel(KRTexture::TEXTURE_USAGE_DIFFUSE_MAP));
}
if(m_pNormalMap) {
stream_level = KRMIN(stream_level, m_pNormalMap->getStreamLevel(KRTexture::TEXTURE_USAGE_NORMAL_MAP));
}
if(m_pSpecularMap) {
stream_level = KRMIN(stream_level, m_pSpecularMap->getStreamLevel(KRTexture::TEXTURE_USAGE_SPECULAR_MAP));
}
if(m_pReflectionMap) {
stream_level = KRMIN(stream_level, m_pReflectionMap->getStreamLevel(KRTexture::TEXTURE_USAGE_REFLECTION_MAP));
}
if(m_pReflectionCube) {
stream_level = KRMIN(stream_level, m_pReflectionCube->getStreamLevel(KRTexture::TEXTURE_USAGE_REFECTION_CUBE));
}
return stream_level;
}
void KRMaterial::getTextures()
{
if(!m_pAmbientMap && m_ambientMap.size()) {
m_pAmbientMap = getContext().getTextureManager()->getTexture(m_ambientMap);
}
if(!m_pDiffuseMap && m_diffuseMap.size()) {
m_pDiffuseMap = getContext().getTextureManager()->getTexture(m_diffuseMap);
}
if(!m_pNormalMap && m_normalMap.size()) {
m_pNormalMap = getContext().getTextureManager()->getTexture(m_normalMap);
}
if(!m_pSpecularMap && m_specularMap.size()) {
m_pSpecularMap = getContext().getTextureManager()->getTexture(m_specularMap);
}
if(!m_pReflectionMap && m_reflectionMap.size()) {
m_pReflectionMap = getContext().getTextureManager()->getTexture(m_reflectionMap);
}
if(!m_pReflectionCube && m_reflectionCube.size()) {
m_pReflectionCube = getContext().getTextureManager()->getTextureCube(m_reflectionCube.c_str());
}
}
bool KRMaterial::bind(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const std::vector<KRBone *> &bones, const std::vector<Matrix4> &bind_poses, const KRViewport &viewport, const Matrix4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const Vector3 &rim_color, float rim_power, float lod_coverage) {
bool bLightMap = pLightMap && pCamera->settings.bEnableLightMap;
getTextures();
Vector2 default_scale = Vector2::One();
Vector2 default_offset = Vector2::Zero();
bool bHasReflection = m_reflectionColor != Vector3::Zero();
bool bDiffuseMap = m_pDiffuseMap != NULL && pCamera->settings.bEnableDiffuseMap;
bool bNormalMap = m_pNormalMap != NULL && pCamera->settings.bEnableNormalMap;
bool bSpecMap = m_pSpecularMap != NULL && pCamera->settings.bEnableSpecMap;
bool bReflectionMap = m_pReflectionMap != NULL && pCamera->settings.bEnableReflectionMap && pCamera->settings.bEnableReflection && bHasReflection;
bool bReflectionCubeMap = m_pReflectionCube != NULL && pCamera->settings.bEnableReflection && bHasReflection;
bool bAlphaTest = (m_alpha_mode == KRMATERIAL_ALPHA_MODE_TEST) && bDiffuseMap;
bool bAlphaBlend = (m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDONESIDE) || (m_alpha_mode == KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE);
KRShader *pShader = getContext().getShaderManager()->getShader("ObjectShader", pCamera, point_lights, directional_lights, spot_lights, bones.size(), bDiffuseMap, bNormalMap, bSpecMap, bReflectionMap, bReflectionCubeMap, bLightMap, m_diffuseMapScale != default_scale && bDiffuseMap, m_specularMapScale != default_scale && bSpecMap, m_normalMapScale != default_scale && bNormalMap, m_reflectionMapScale != default_scale && bReflectionMap, m_diffuseMapOffset != default_offset && bDiffuseMap, m_specularMapOffset != default_offset && bSpecMap, m_normalMapOffset != default_offset && bNormalMap, m_reflectionMapOffset != default_offset && bReflectionMap, bAlphaTest, bAlphaBlend, renderPass, rim_power != 0.0f);
Vector4 fade_color;
if(!getContext().getShaderManager()->selectShader(*pCamera, pShader, viewport, matModel, point_lights, directional_lights, spot_lights, 0, renderPass, rim_color, rim_power, fade_color)) {
return false;
}
// Bind bones
if(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS] != -1) {
GLfloat bone_mats[256 * 16];
GLfloat *bone_mat_component = bone_mats;
for(int bone_index=0; bone_index < bones.size(); bone_index++) {
KRBone *bone = bones[bone_index];
// Vector3 initialRotation = bone->getInitialLocalRotation();
// Vector3 rotation = bone->getLocalRotation();
// Vector3 initialTranslation = bone->getInitialLocalTranslation();
// Vector3 translation = bone->getLocalTranslation();
// Vector3 initialScale = bone->getInitialLocalScale();
// Vector3 scale = bone->getLocalScale();
//
//printf("%s - delta rotation: %.4f %.4f %.4f\n", bone->getName().c_str(), (rotation.x - initialRotation.x) * 180.0 / M_PI, (rotation.y - initialRotation.y) * 180.0 / M_PI, (rotation.z - initialRotation.z) * 180.0 / M_PI);
//printf("%s - delta translation: %.4f %.4f %.4f\n", bone->getName().c_str(), translation.x - initialTranslation.x, translation.y - initialTranslation.y, translation.z - initialTranslation.z);
// printf("%s - delta scale: %.4f %.4f %.4f\n", bone->getName().c_str(), scale.x - initialScale.x, scale.y - initialScale.y, scale.z - initialScale.z);
Matrix4 skin_bone_bind_pose = bind_poses[bone_index];
Matrix4 active_mat = bone->getActivePoseMatrix();
Matrix4 inv_bind_mat = bone->getInverseBindPoseMatrix();
Matrix4 inv_bind_mat2 = Matrix4::Invert(bind_poses[bone_index]);
Matrix4 t = (inv_bind_mat * active_mat);
Matrix4 t2 = inv_bind_mat2 * bone->getModelMatrix();
for(int i=0; i < 16; i++) {
*bone_mat_component++ = t[i];
}
}
if(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS] != -1) {
glUniformMatrix4fv(pShader->m_uniforms[KRShader::KRENGINE_UNIFORM_BONE_TRANSFORMS], bones.size(), GL_FALSE, bone_mats);
}
}
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_AMBIENT, m_ambientColor + pCamera->settings.ambient_intensity);
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE) {
// We pre-multiply the light color with the material color in the forward renderer
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_DIFFUSE, Vector3::Create(m_diffuseColor.x * pCamera->settings.light_intensity.x, m_diffuseColor.y * pCamera->settings.light_intensity.y, m_diffuseColor.z * pCamera->settings.light_intensity.z));
} else {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_DIFFUSE, m_diffuseColor);
}
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE) {
// We pre-multiply the light color with the material color in the forward renderer
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SPECULAR, Vector3::Create(m_specularColor.x * pCamera->settings.light_intensity.x, m_specularColor.y * pCamera->settings.light_intensity.y, m_specularColor.z * pCamera->settings.light_intensity.z));
} else {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SPECULAR, m_specularColor);
}
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_SHININESS, m_ns);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_REFLECTION, m_reflectionColor);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_DIFFUSETEXTURE_SCALE, m_diffuseMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_SPECULARTEXTURE_SCALE, m_specularMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_REFLECTIONTEXTURE_SCALE, m_reflectionMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_NORMALTEXTURE_SCALE, m_normalMapScale);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_DIFFUSETEXTURE_OFFSET, m_diffuseMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_SPECULARTEXTURE_OFFSET, m_specularMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_REFLECTIONTEXTURE_OFFSET, m_reflectionMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_NORMALTEXTURE_OFFSET, m_normalMapOffset);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_tr);
if(bDiffuseMap) {
m_pContext->getTextureManager()->selectTexture(0, m_pDiffuseMap, lod_coverage, KRTexture::TEXTURE_USAGE_DIFFUSE_MAP);
}
if(bSpecMap) {
m_pContext->getTextureManager()->selectTexture(1, m_pSpecularMap, lod_coverage, KRTexture::TEXTURE_USAGE_SPECULAR_MAP);
}
if(bNormalMap) {
m_pContext->getTextureManager()->selectTexture(2, m_pNormalMap, lod_coverage, KRTexture::TEXTURE_USAGE_NORMAL_MAP);
}
if(bReflectionCubeMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) {
m_pContext->getTextureManager()->selectTexture(4, m_pReflectionCube, lod_coverage, KRTexture::TEXTURE_USAGE_REFECTION_CUBE);
}
if(bReflectionMap && (renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE)) {
// GL_TEXTURE7 is used for reading the depth buffer in gBuffer pass 2 and re-used for the reflection map in gBuffer Pass 3 and in forward rendering
m_pContext->getTextureManager()->selectTexture(7, m_pReflectionMap, lod_coverage, KRTexture::TEXTURE_USAGE_REFLECTION_MAP);
}
return true;
}
const std::string &KRMaterial::getName() const
{
return m_name;
}

View File

@@ -1,288 +1,288 @@
//
// KRMaterialManager.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.
//
#include "KREngine-common.h"
#include "KRMaterialManager.h"
KRMaterialManager::KRMaterialManager(KRContext &context, KRTextureManager *pTextureManager, KRShaderManager *pShaderManager) : KRContextObject(context)
{
m_pTextureManager = pTextureManager;
m_pShaderManager = pShaderManager;
}
KRMaterialManager::~KRMaterialManager() {
}
unordered_map<std::string, KRMaterial *> &KRMaterialManager::getMaterials()
{
return m_materials;
}
void KRMaterialManager::configure(bool blend_enable, GLenum blend_src, GLenum blend_dest, bool depth_test_enable, GLenum depth_func, bool depth_write_enable) {
if(blend_enable) {
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(blend_src, blend_dest));
} else {
GLDEBUG(glDisable(GL_BLEND));
}
if(depth_test_enable) {
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(depth_func));
} else {
GLDEBUG(glDisable(GL_DEPTH_TEST));
}
if(depth_write_enable) {
GLDEBUG(glDepthMask(GL_TRUE));
} else {
GLDEBUG(glDepthMask(GL_FALSE));
}
}
KRMaterial *KRMaterialManager::getMaterial(const std::string &name) {
std::string lowerName = name;
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
unordered_map<std::string, KRMaterial *>::iterator itr = m_materials.find(lowerName);
if(itr == m_materials.end()) {
KRContext::Log(KRContext::LOG_LEVEL_WARNING, "Material not found: %s", name.c_str());
// Not found
return NULL;
} else {
return (*itr).second;
}
}
void KRMaterialManager::add(KRMaterial *new_material) {
// FINDME, TODO - Potential memory leak if multiple materials with the same name are added
std::string lowerName = new_material->getName();
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
m_materials[lowerName] = new_material;
}
bool KRMaterialManager::load(const char *szName, KRDataBlock *data) {
KRMaterial *pMaterial = NULL;
char szSymbol[16][256];
data->lock();
char *pScan = (char *)data->getStart();
char *pEnd = (char *)data->getEnd();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
if(*pScan >= 'A' && *pScan <= 'Z') {
*pDest++ = *pScan++ + 'a' - 'A'; // convert to lower case for case sensitve comparison later
} else {
*pDest++ = *pScan++;
}
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(cSymbols > 0) {
if(strcmp(szSymbol[0], "newmtl") == 0 && cSymbols >= 2) {
pMaterial = new KRMaterial(*m_pContext, szSymbol[1]);
m_materials[szSymbol[1]] = pMaterial;
}
if(pMaterial != NULL) {
if(strcmp(szSymbol[0], "alpha_mode") == 0) {
if(cSymbols == 2) {
if(strcmp(szSymbol[1], "test") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_TEST);
} else if(strcmp(szSymbol[1], "blendoneside") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE);
} else if(strcmp(szSymbol[1], "blendtwoside") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE);
} else {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE);
}
}
} else if(strcmp(szSymbol[0], "ka") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setAmbient(Vector3(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setAmbient(Vector3(r, g, b));
}
} else if(strcmp(szSymbol[0], "kd") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setDiffuse(Vector3(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setDiffuse(Vector3(r, g, b));
}
} else if(strcmp(szSymbol[0], "ks") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setSpecular(Vector3(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setSpecular(Vector3(r, g, b));
}
} else if(strcmp(szSymbol[0], "kr") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setReflection(Vector3(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setReflection(Vector3(r, g, b));
}
} else if(strcmp(szSymbol[0], "tr") == 0) {
char *pScan2 = szSymbol[1];
float a = strtof(pScan2, &pScan2);
pMaterial->setTransparency(a);
} else if(strcmp(szSymbol[0], "ns") == 0) {
char *pScan2 = szSymbol[1];
float a = strtof(pScan2, &pScan2);
pMaterial->setShininess(a);
} else if(strncmp(szSymbol[0], "map", 3) == 0) {
// Truncate file extension
char *pScan2 = szSymbol[1];
char *pLastPeriod = NULL;
while(*pScan2 != '\0') {
if(*pScan2 == '.') {
pLastPeriod = pScan2;
}
pScan2++;
}
if(pLastPeriod) {
*pLastPeriod = '\0';
}
Vector2 texture_scale = Vector2(1.0f, 1.0f);
Vector2 texture_offset = Vector2(0.0f, 0.0f);
int iScanSymbol = 2;
int iScaleParam = -1;
int iOffsetParam = -1;
while(iScanSymbol < cSymbols) {
if(strcmp(szSymbol[iScanSymbol], "-s") == 0) {
// Scale
iScaleParam = 0;
iOffsetParam = -1;
} else if(strcmp(szSymbol[iScanSymbol], "-o") == 0) {
// Offset
iOffsetParam = 0;
iScaleParam = -1;
} else {
char *pScan3 = szSymbol[iScanSymbol];
float v = strtof(pScan3, &pScan3);
if(iScaleParam == 0) {
texture_scale.x = v;
iScaleParam++;
} else if(iScaleParam == 1) {
texture_scale.y = v;
iScaleParam++;
} else if(iOffsetParam == 0) {
texture_offset.x = v;
iOffsetParam++;
} else if(iOffsetParam == 1) {
texture_offset.y = v;
iOffsetParam++;
}
}
iScanSymbol++;
}
if(strcmp(szSymbol[0], "map_ka") == 0) {
pMaterial->setAmbientMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_kd") == 0) {
pMaterial->setDiffuseMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_ks") == 0) {
pMaterial->setSpecularMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_normal") == 0) {
pMaterial->setNormalMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_reflection") == 0) {
pMaterial->setReflectionMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_reflectioncube") == 0) {
pMaterial->setReflectionCube(szSymbol[1]);
}
}
}
}
}
}
data->unlock();
delete data;
return true;
}
//
// KRMaterialManager.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.
//
#include "KREngine-common.h"
#include "KRMaterialManager.h"
KRMaterialManager::KRMaterialManager(KRContext &context, KRTextureManager *pTextureManager, KRShaderManager *pShaderManager) : KRContextObject(context)
{
m_pTextureManager = pTextureManager;
m_pShaderManager = pShaderManager;
}
KRMaterialManager::~KRMaterialManager() {
}
unordered_map<std::string, KRMaterial *> &KRMaterialManager::getMaterials()
{
return m_materials;
}
void KRMaterialManager::configure(bool blend_enable, GLenum blend_src, GLenum blend_dest, bool depth_test_enable, GLenum depth_func, bool depth_write_enable) {
if(blend_enable) {
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(blend_src, blend_dest));
} else {
GLDEBUG(glDisable(GL_BLEND));
}
if(depth_test_enable) {
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(depth_func));
} else {
GLDEBUG(glDisable(GL_DEPTH_TEST));
}
if(depth_write_enable) {
GLDEBUG(glDepthMask(GL_TRUE));
} else {
GLDEBUG(glDepthMask(GL_FALSE));
}
}
KRMaterial *KRMaterialManager::getMaterial(const std::string &name) {
std::string lowerName = name;
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
unordered_map<std::string, KRMaterial *>::iterator itr = m_materials.find(lowerName);
if(itr == m_materials.end()) {
KRContext::Log(KRContext::LOG_LEVEL_WARNING, "Material not found: %s", name.c_str());
// Not found
return NULL;
} else {
return (*itr).second;
}
}
void KRMaterialManager::add(KRMaterial *new_material) {
// FINDME, TODO - Potential memory leak if multiple materials with the same name are added
std::string lowerName = new_material->getName();
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
m_materials[lowerName] = new_material;
}
bool KRMaterialManager::load(const char *szName, KRDataBlock *data) {
KRMaterial *pMaterial = NULL;
char szSymbol[16][256];
data->lock();
char *pScan = (char *)data->getStart();
char *pEnd = (char *)data->getEnd();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
if(*pScan >= 'A' && *pScan <= 'Z') {
*pDest++ = *pScan++ + 'a' - 'A'; // convert to lower case for case sensitve comparison later
} else {
*pDest++ = *pScan++;
}
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(cSymbols > 0) {
if(strcmp(szSymbol[0], "newmtl") == 0 && cSymbols >= 2) {
pMaterial = new KRMaterial(*m_pContext, szSymbol[1]);
m_materials[szSymbol[1]] = pMaterial;
}
if(pMaterial != NULL) {
if(strcmp(szSymbol[0], "alpha_mode") == 0) {
if(cSymbols == 2) {
if(strcmp(szSymbol[1], "test") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_TEST);
} else if(strcmp(szSymbol[1], "blendoneside") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDONESIDE);
} else if(strcmp(szSymbol[1], "blendtwoside") == 0) {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE);
} else {
pMaterial->setAlphaMode(KRMaterial::KRMATERIAL_ALPHA_MODE_OPAQUE);
}
}
} else if(strcmp(szSymbol[0], "ka") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setAmbient(Vector3::Create(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setAmbient(Vector3::Create(r, g, b));
}
} else if(strcmp(szSymbol[0], "kd") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setDiffuse(Vector3::Create(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setDiffuse(Vector3::Create(r, g, b));
}
} else if(strcmp(szSymbol[0], "ks") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setSpecular(Vector3::Create(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setSpecular(Vector3::Create(r, g, b));
}
} else if(strcmp(szSymbol[0], "kr") == 0) {
char *pScan2 = szSymbol[1];
float r = strtof(pScan2, &pScan2);
if(cSymbols == 2) {
pMaterial->setReflection(Vector3::Create(r, r, r));
} else if(cSymbols == 4) {
pScan2 = szSymbol[2];
float g = strtof(pScan2, &pScan2);
pScan2 = szSymbol[3];
float b = strtof(pScan2, &pScan2);
pMaterial->setReflection(Vector3::Create(r, g, b));
}
} else if(strcmp(szSymbol[0], "tr") == 0) {
char *pScan2 = szSymbol[1];
float a = strtof(pScan2, &pScan2);
pMaterial->setTransparency(a);
} else if(strcmp(szSymbol[0], "ns") == 0) {
char *pScan2 = szSymbol[1];
float a = strtof(pScan2, &pScan2);
pMaterial->setShininess(a);
} else if(strncmp(szSymbol[0], "map", 3) == 0) {
// Truncate file extension
char *pScan2 = szSymbol[1];
char *pLastPeriod = NULL;
while(*pScan2 != '\0') {
if(*pScan2 == '.') {
pLastPeriod = pScan2;
}
pScan2++;
}
if(pLastPeriod) {
*pLastPeriod = '\0';
}
Vector2 texture_scale = Vector2::Create(1.0f, 1.0f);
Vector2 texture_offset = Vector2::Create(0.0f, 0.0f);
int iScanSymbol = 2;
int iScaleParam = -1;
int iOffsetParam = -1;
while(iScanSymbol < cSymbols) {
if(strcmp(szSymbol[iScanSymbol], "-s") == 0) {
// Scale
iScaleParam = 0;
iOffsetParam = -1;
} else if(strcmp(szSymbol[iScanSymbol], "-o") == 0) {
// Offset
iOffsetParam = 0;
iScaleParam = -1;
} else {
char *pScan3 = szSymbol[iScanSymbol];
float v = strtof(pScan3, &pScan3);
if(iScaleParam == 0) {
texture_scale.x = v;
iScaleParam++;
} else if(iScaleParam == 1) {
texture_scale.y = v;
iScaleParam++;
} else if(iOffsetParam == 0) {
texture_offset.x = v;
iOffsetParam++;
} else if(iOffsetParam == 1) {
texture_offset.y = v;
iOffsetParam++;
}
}
iScanSymbol++;
}
if(strcmp(szSymbol[0], "map_ka") == 0) {
pMaterial->setAmbientMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_kd") == 0) {
pMaterial->setDiffuseMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_ks") == 0) {
pMaterial->setSpecularMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_normal") == 0) {
pMaterial->setNormalMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_reflection") == 0) {
pMaterial->setReflectionMap(szSymbol[1], texture_scale, texture_offset);
} else if(strcmp(szSymbol[0], "map_reflectioncube") == 0) {
pMaterial->setReflectionCube(szSymbol[1]);
}
}
}
}
}
}
data->unlock();
delete data;
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,290 +1,292 @@
//
// KRMesh.h
// 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.
//
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRBone.h"
#include "KRMeshManager.h"
#include "KREngine-common.h"
using namespace kraken;
#define MAX_VBO_SIZE 65535
#define KRENGINE_MAX_BONE_WEIGHTS_PER_VERTEX 4
#define KRENGINE_MAX_NAME_LENGTH 256
// MAX_VBO_SIZE must be divisible by 3 so triangles aren't split across VBO objects...
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#ifndef KRMesh_I
#define KRMesh_I
#include "KRMaterialManager.h"
#include "KRCamera.h"
#include "KRViewport.h"
class KRMaterial;
class KRNode;
class KRMesh : public KRResource {
public:
KRMesh(KRContext &context, std::string name, KRDataBlock *data);
KRMesh(KRContext &context, std::string name);
virtual ~KRMesh();
kraken_stream_level getStreamLevel();
void preStream(float lodCoverage);
bool hasTransparency();
typedef enum {
KRENGINE_ATTRIB_VERTEX = 0,
KRENGINE_ATTRIB_NORMAL,
KRENGINE_ATTRIB_TANGENT,
KRENGINE_ATTRIB_TEXUVA,
KRENGINE_ATTRIB_TEXUVB,
KRENGINE_ATTRIB_BONEINDEXES,
KRENGINE_ATTRIB_BONEWEIGHTS,
KRENGINE_ATTRIB_VERTEX_SHORT,
KRENGINE_ATTRIB_NORMAL_SHORT,
KRENGINE_ATTRIB_TANGENT_SHORT,
KRENGINE_ATTRIB_TEXUVA_SHORT,
KRENGINE_ATTRIB_TEXUVB_SHORT,
KRENGINE_NUM_ATTRIBUTES
} vertex_attrib_t;
typedef enum {
KRENGINE_MODEL_FORMAT_TRIANGLES = 0,
KRENGINE_MODEL_FORMAT_STRIP,
KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES,
KRENGINE_MODEL_FORMAT_INDEXED_STRIP
} model_format_t;
typedef struct {
model_format_t format;
std::vector<Vector3> vertices;
std::vector<__uint16_t> vertex_indexes;
std::vector<std::pair<int, int> > vertex_index_bases;
std::vector<Vector2> uva;
std::vector<Vector2> uvb;
std::vector<Vector3> normals;
std::vector<Vector3> tangents;
std::vector<int> submesh_starts;
std::vector<int> submesh_lengths;
std::vector<std::string> material_names;
std::vector<std::string> bone_names;
std::vector<std::vector<int> > bone_indexes;
std::vector<Matrix4> bone_bind_poses;
std::vector<std::vector<float> > bone_weights;
} mesh_info;
void render(const std::string &object_name, KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, const Matrix4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector<KRBone *> &bones, const Vector3 &rim_color, float rim_power, float lod_coverage = 0.0f);
std::string m_lodBaseName;
virtual std::string getExtension();
virtual bool save(const std::string& path);
virtual bool save(KRDataBlock &data);
void LoadData(const mesh_info &mi, bool calculate_normals, bool calculate_tangents);
void loadPack(KRDataBlock *data);
void convertToIndexed();
void optimize();
void optimizeIndexes();
void renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name, float lodCoverage);
GLfloat getMaxDimension();
Vector3 getMinPoint() const;
Vector3 getMaxPoint() const;
class Submesh {
public:
Submesh() {};
~Submesh() {
for(auto itr = vbo_data_blocks.begin(); itr != vbo_data_blocks.end(); itr++) {
delete (*itr);
}
for(auto itr = vertex_data_blocks.begin(); itr != vertex_data_blocks.end(); itr++) {
delete (*itr);
}
for(auto itr = index_data_blocks.begin(); itr != index_data_blocks.end(); itr++) {
delete (*itr);
}
};
GLint start_vertex;
GLsizei vertex_count;
char szMaterialName[KRENGINE_MAX_NAME_LENGTH];
vector<KRDataBlock *> vertex_data_blocks;
vector<KRDataBlock *> index_data_blocks;
vector<KRMeshManager::KRVBOData *> vbo_data_blocks;
};
typedef struct {
union {
struct { // For Indexed triangles / strips
uint16_t index_group;
uint16_t index_group_offset;
};
int32_t start_vertex; // For non-indexed trigangles / strips
};
int32_t vertex_count;
char szName[KRENGINE_MAX_NAME_LENGTH];
} pack_material;
typedef struct {
char szName[KRENGINE_MAX_NAME_LENGTH];
float bind_pose[16];
} pack_bone;
int getLODCoverage() const;
std::string getLODBaseName() const;
static bool lod_sort_predicate(const KRMesh *m1, const KRMesh *m2);
bool has_vertex_attribute(vertex_attrib_t attribute_type) const;
static bool has_vertex_attribute(int vertex_attrib_flags, vertex_attrib_t attribute_type);
int getSubmeshCount() const;
int getVertexCount(int submesh) const;
int getTriangleVertexIndex(int submesh, int index) const;
Vector3 getVertexPosition(int index) const;
Vector3 getVertexNormal(int index) const;
Vector3 getVertexTangent(int index) const;
Vector2 getVertexUVA(int index) const;
Vector2 getVertexUVB(int index) const;
int getBoneIndex(int index, int weight_index) const;
float getBoneWeight(int index, int weight_index) const;
void setVertexPosition(int index, const Vector3 &v);
void setVertexNormal(int index, const Vector3 &v);
void setVertexTangent(int index, const Vector3 & v);
void setVertexUVA(int index, const Vector2 &v);
void setVertexUVB(int index, const Vector2 &v);
void setBoneIndex(int index, int weight_index, int bone_index);
void setBoneWeight(int index, int weight_index, float bone_weight);
static size_t VertexSizeForAttributes(__int32_t vertex_attrib_flags);
static size_t AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_flags);
int getBoneCount();
char *getBoneName(int bone_index);
Matrix4 getBoneBindPose(int bone_index);
model_format_t getModelFormat() const;
bool lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo) const;
bool rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo) const;
bool sphereCast(const Matrix4 &model_to_world, const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo) const;
static int GetLODCoverage(const std::string &name);
void load(); // Load immediately into the GPU rather than passing through the streamer
protected:
bool m_constant; // TRUE if this should be always loaded and should not be passed through the streamer
private:
KRDataBlock *m_pData;
KRDataBlock *m_pMetaData;
KRDataBlock *m_pIndexBaseData;
void getSubmeshes();
void getMaterials();
static bool rayCast(const Vector3 &start, const Vector3 &dir, const Triangle3 &tri, const Vector3 &tri_n0, const Vector3 &tri_n1, const Vector3 &tri_n2, HitInfo &hitinfo);
static bool sphereCast(const Matrix4 &model_to_world, const Vector3 &v0, const Vector3 &v1, float radius, const Triangle3 &tri, HitInfo &hitinfo);
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
vector<KRMaterial *> m_materials;
set<KRMaterial *> m_uniqueMaterials;
bool m_hasTransparency;
Vector3 m_minPoint, m_maxPoint;
typedef struct {
char szTag[16];
int32_t model_format; // 0 == Triangle list, 1 == Triangle strips, 2 == Indexed triangle list, 3 == Indexed triangle strips, rest are reserved (model_format_t enum)
int32_t vertex_attrib_flags;
int32_t vertex_count;
int32_t submesh_count;
int32_t bone_count;
float minx, miny, minz, maxx, maxy, maxz; // Axis aligned bounding box, in model's coordinate space
int32_t index_count;
int32_t index_base_count;
unsigned char reserved[444]; // Pad out to 512 bytes
} pack_header;
vector<Submesh *> m_submeshes;
int m_vertex_attribute_offset[KRENGINE_NUM_ATTRIBUTES];
int m_vertex_size;
void updateAttributeOffsets();
void setName(const std::string name);
pack_material *getSubmesh(int mesh_index) const;
unsigned char *getVertexData() const;
size_t getVertexDataOffset() const;
unsigned char *getVertexData(int index) const;
__uint16_t *getIndexData() const;
size_t getIndexDataOffset() const;
__uint32_t *getIndexBaseData() const;
pack_header *getHeader() const;
pack_bone *getBone(int index);
void getIndexedRange(int index_group, int &start_index_offset, int &start_vertex_offset, int &index_count, int &vertex_count) const;
void releaseData();
void createDataBlocks(KRMeshManager::KRVBOData::vbo_type t);
};
//
// KRMesh.h
// 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.
//
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRBone.h"
#include "KRMeshManager.h"
#include "KREngine-common.h"
#include "hydra.h"
using namespace kraken;
#define MAX_VBO_SIZE 65535
#define KRENGINE_MAX_BONE_WEIGHTS_PER_VERTEX 4
#define KRENGINE_MAX_NAME_LENGTH 256
// MAX_VBO_SIZE must be divisible by 3 so triangles aren't split across VBO objects...
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#ifndef KRMesh_I
#define KRMesh_I
#include "KRMaterialManager.h"
#include "KRCamera.h"
#include "KRViewport.h"
class KRMaterial;
class KRNode;
class KRMesh : public KRResource {
public:
KRMesh(KRContext &context, std::string name, KRDataBlock *data);
KRMesh(KRContext &context, std::string name);
virtual ~KRMesh();
kraken_stream_level getStreamLevel();
void preStream(float lodCoverage);
bool hasTransparency();
typedef enum {
KRENGINE_ATTRIB_VERTEX = 0,
KRENGINE_ATTRIB_NORMAL,
KRENGINE_ATTRIB_TANGENT,
KRENGINE_ATTRIB_TEXUVA,
KRENGINE_ATTRIB_TEXUVB,
KRENGINE_ATTRIB_BONEINDEXES,
KRENGINE_ATTRIB_BONEWEIGHTS,
KRENGINE_ATTRIB_VERTEX_SHORT,
KRENGINE_ATTRIB_NORMAL_SHORT,
KRENGINE_ATTRIB_TANGENT_SHORT,
KRENGINE_ATTRIB_TEXUVA_SHORT,
KRENGINE_ATTRIB_TEXUVB_SHORT,
KRENGINE_NUM_ATTRIBUTES
} vertex_attrib_t;
typedef enum {
KRENGINE_MODEL_FORMAT_TRIANGLES = 0,
KRENGINE_MODEL_FORMAT_STRIP,
KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES,
KRENGINE_MODEL_FORMAT_INDEXED_STRIP
} model_format_t;
typedef struct {
model_format_t format;
std::vector<Vector3> vertices;
std::vector<__uint16_t> vertex_indexes;
std::vector<std::pair<int, int> > vertex_index_bases;
std::vector<Vector2> uva;
std::vector<Vector2> uvb;
std::vector<Vector3> normals;
std::vector<Vector3> tangents;
std::vector<int> submesh_starts;
std::vector<int> submesh_lengths;
std::vector<std::string> material_names;
std::vector<std::string> bone_names;
std::vector<std::vector<int> > bone_indexes;
std::vector<Matrix4> bone_bind_poses;
std::vector<std::vector<float> > bone_weights;
} mesh_info;
void render(const std::string &object_name, KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, const Matrix4 &matModel, KRTexture *pLightMap, KRNode::RenderPass renderPass, const std::vector<KRBone *> &bones, const Vector3 &rim_color, float rim_power, float lod_coverage = 0.0f);
std::string m_lodBaseName;
virtual std::string getExtension();
virtual bool save(const std::string& path);
virtual bool save(KRDataBlock &data);
void LoadData(const mesh_info &mi, bool calculate_normals, bool calculate_tangents);
void loadPack(KRDataBlock *data);
void convertToIndexed();
void optimize();
void optimizeIndexes();
void renderSubmesh(int iSubmesh, KRNode::RenderPass renderPass, const std::string &object_name, const std::string &material_name, float lodCoverage);
GLfloat getMaxDimension();
Vector3 getMinPoint() const;
Vector3 getMaxPoint() const;
class Submesh {
public:
Submesh() {};
~Submesh() {
for(auto itr = vbo_data_blocks.begin(); itr != vbo_data_blocks.end(); itr++) {
delete (*itr);
}
for(auto itr = vertex_data_blocks.begin(); itr != vertex_data_blocks.end(); itr++) {
delete (*itr);
}
for(auto itr = index_data_blocks.begin(); itr != index_data_blocks.end(); itr++) {
delete (*itr);
}
};
GLint start_vertex;
GLsizei vertex_count;
char szMaterialName[KRENGINE_MAX_NAME_LENGTH];
vector<KRDataBlock *> vertex_data_blocks;
vector<KRDataBlock *> index_data_blocks;
vector<KRMeshManager::KRVBOData *> vbo_data_blocks;
};
typedef struct {
union {
struct { // For Indexed triangles / strips
uint16_t index_group;
uint16_t index_group_offset;
};
int32_t start_vertex; // For non-indexed trigangles / strips
};
int32_t vertex_count;
char szName[KRENGINE_MAX_NAME_LENGTH];
} pack_material;
typedef struct {
char szName[KRENGINE_MAX_NAME_LENGTH];
float bind_pose[16];
} pack_bone;
int getLODCoverage() const;
std::string getLODBaseName() const;
static bool lod_sort_predicate(const KRMesh *m1, const KRMesh *m2);
bool has_vertex_attribute(vertex_attrib_t attribute_type) const;
static bool has_vertex_attribute(int vertex_attrib_flags, vertex_attrib_t attribute_type);
int getSubmeshCount() const;
int getVertexCount(int submesh) const;
int getTriangleVertexIndex(int submesh, int index) const;
Vector3 getVertexPosition(int index) const;
Vector3 getVertexNormal(int index) const;
Vector3 getVertexTangent(int index) const;
Vector2 getVertexUVA(int index) const;
Vector2 getVertexUVB(int index) const;
int getBoneIndex(int index, int weight_index) const;
float getBoneWeight(int index, int weight_index) const;
void setVertexPosition(int index, const Vector3 &v);
void setVertexNormal(int index, const Vector3 &v);
void setVertexTangent(int index, const Vector3 & v);
void setVertexUVA(int index, const Vector2 &v);
void setVertexUVB(int index, const Vector2 &v);
void setBoneIndex(int index, int weight_index, int bone_index);
void setBoneWeight(int index, int weight_index, float bone_weight);
static size_t VertexSizeForAttributes(__int32_t vertex_attrib_flags);
static size_t AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_flags);
int getBoneCount();
char *getBoneName(int bone_index);
Matrix4 getBoneBindPose(int bone_index);
model_format_t getModelFormat() const;
bool lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo) const;
bool rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo) const;
bool sphereCast(const Matrix4 &model_to_world, const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo) const;
static int GetLODCoverage(const std::string &name);
void load(); // Load immediately into the GPU rather than passing through the streamer
protected:
bool m_constant; // TRUE if this should be always loaded and should not be passed through the streamer
private:
KRDataBlock *m_pData;
KRDataBlock *m_pMetaData;
KRDataBlock *m_pIndexBaseData;
void getSubmeshes();
void getMaterials();
static bool rayCast(const Vector3 &start, const Vector3 &dir, const Triangle3 &tri, const Vector3 &tri_n0, const Vector3 &tri_n1, const Vector3 &tri_n2, HitInfo &hitinfo);
static bool sphereCast(const Matrix4 &model_to_world, const Vector3 &v0, const Vector3 &v1, float radius, const Triangle3 &tri, HitInfo &hitinfo);
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
vector<KRMaterial *> m_materials;
set<KRMaterial *> m_uniqueMaterials;
bool m_hasTransparency;
Vector3 m_minPoint, m_maxPoint;
typedef struct {
char szTag[16];
int32_t model_format; // 0 == Triangle list, 1 == Triangle strips, 2 == Indexed triangle list, 3 == Indexed triangle strips, rest are reserved (model_format_t enum)
int32_t vertex_attrib_flags;
int32_t vertex_count;
int32_t submesh_count;
int32_t bone_count;
float minx, miny, minz, maxx, maxy, maxz; // Axis aligned bounding box, in model's coordinate space
int32_t index_count;
int32_t index_base_count;
unsigned char reserved[444]; // Pad out to 512 bytes
} pack_header;
vector<Submesh *> m_submeshes;
int m_vertex_attribute_offset[KRENGINE_NUM_ATTRIBUTES];
int m_vertex_size;
void updateAttributeOffsets();
void setName(const std::string name);
pack_material *getSubmesh(int mesh_index) const;
unsigned char *getVertexData() const;
size_t getVertexDataOffset() const;
unsigned char *getVertexData(int index) const;
__uint16_t *getIndexData() const;
size_t getIndexDataOffset() const;
__uint32_t *getIndexBaseData() const;
pack_header *getHeader() const;
pack_bone *getBone(int index);
void getIndexedRange(int index_group, int &start_index_offset, int &start_vertex_offset, int &index_count, int &vertex_count) const;
void releaseData();
void createDataBlocks(KRMeshManager::KRVBOData::vbo_type t);
};
#endif // KRMesh_I

View File

@@ -1,69 +1,69 @@
//
// KRMeshCube.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.
//
#include "KRMeshCube.h"
KRMeshCube::KRMeshCube(KRContext &context) : KRMesh(context, "__cube")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3(1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3(-1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3(-1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3(-1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3(1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3(1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3(1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3(-1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3(1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3(-1.0, 1.0,-1.0));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshCube::~KRMeshCube()
{
}
//
// KRMeshCube.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.
//
#include "KRMeshCube.h"
KRMeshCube::KRMeshCube(KRContext &context) : KRMesh(context, "__cube")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3::Create(1.0,-1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3::Create(-1.0,-1.0,-1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0,-1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0,-1.0));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshCube::~KRMeshCube()
{
}

View File

@@ -1,207 +1,207 @@
//
// KRMeshManager.h
// 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.
//
#ifndef KRMESHMANAGER_H
#define KRMESHMANAGER_H
#include "KREngine-common.h"
#include "KRContextObject.h"
#include "KRDataBlock.h"
#include "KRNode.h"
class KRContext;
class KRMesh;
class KRMeshManager : public KRContextObject {
public:
static const int KRENGINE_MAX_VOLUMETRIC_PLANES=500;
static const int KRENGINE_MAX_RANDOM_PARTICLES=150000;
KRMeshManager(KRContext &context);
virtual ~KRMeshManager();
void startFrame(float deltaTime);
void endFrame(float deltaTime);
void firstFrame();
KRMesh *loadModel(const char *szName, KRDataBlock *pData);
std::vector<KRMesh *> getModel(const char *szName);
void addModel(KRMesh *model);
std::vector<std::string> getModelNames();
unordered_multimap<std::string, KRMesh *> &getModels();
class KRVBOData {
public:
typedef enum {
STREAMING,
CONSTANT,
TEMPORARY
} vbo_type;
KRVBOData();
KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t);
void init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t);
~KRVBOData();
KRDataBlock *m_data;
KRDataBlock *m_index_data;
bool isVBOLoaded() { return m_is_vbo_loaded; }
bool isVBOReady() { return m_is_vbo_ready; }
void load();
void unload();
void bind();
// Disable copy constructors
KRVBOData(const KRVBOData& o) = delete;
KRVBOData(KRVBOData& o) = delete;
long getSize() { return m_size; }
void resetPoolExpiry(float lodCoverage);
long getLastFrameUsed() { return m_last_frame_used; }
vbo_type getType() { return m_type; }
float getStreamPriority();
void _swapHandles();
private:
KRMeshManager *m_manager;
int m_vertex_attrib_flags;
GLuint m_vbo_handle;
GLuint m_vbo_handle_indexes;
GLuint m_vao_handle;
GLsizeiptr m_size;
long m_last_frame_used;
float m_last_frame_max_lod_coverage;
vbo_type m_type;
bool m_static_vbo;
bool m_is_vbo_loaded;
bool m_is_vbo_ready;
};
void bindVBO(KRVBOData *vbo_data, float lodCoverage);
void bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, float lodCoverage);
void unbindVBO();
long getMemUsed();
long getMemActive();
static void configureAttribs(__int32_t attributes);
typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vector3D;
typedef struct {
GLfloat u;
GLfloat v;
} TexCoord;
typedef struct {
Vector3D vertex;
TexCoord uva;
} RandomParticleVertexData;
typedef struct {
Vector3D vertex;
} VolumetricLightingVertexData;
KRDataBlock &getRandomParticles();
KRDataBlock &getVolumetricLightingVertexes();
long getMemoryTransferedThisFrame();
int getActiveVBOCount();
struct draw_call_info {
KRNode::RenderPass pass;
char object_name[256];
char material_name[256];
int vertex_count;
};
void log_draw_call(KRNode::RenderPass pass, const std::string &object_name, const std::string &material_name, int vertex_count);
std::vector<draw_call_info> getDrawCalls();
KRVBOData KRENGINE_VBO_DATA_3D_CUBE_VERTICES;
KRVBOData KRENGINE_VBO_DATA_2D_SQUARE_VERTICES;
void doStreaming(long &memoryRemaining, long &memoryRemainingThisFrame);
private:
KRDataBlock KRENGINE_VBO_3D_CUBE_VERTICES, KRENGINE_VBO_3D_CUBE_INDEXES;
__int32_t KRENGINE_VBO_3D_CUBE_ATTRIBS;
KRDataBlock KRENGINE_VBO_2D_SQUARE_VERTICES, KRENGINE_VBO_2D_SQUARE_INDEXES;
__int32_t KRENGINE_VBO_2D_SQUARE_ATTRIBS;
unordered_multimap<std::string, KRMesh *> m_models; // Multiple models with the same name/key may be inserted, representing multiple LOD levels of the model
long m_vboMemUsed;
KRVBOData *m_currentVBO;
unordered_map<KRDataBlock *, KRVBOData *> m_vbosActive;
std::vector<std::pair<float, KRVBOData *> > m_activeVBOs_streamer;
std::vector<std::pair<float, KRVBOData *> > m_activeVBOs_streamer_copy;
KRDataBlock m_randomParticleVertexData;
KRDataBlock m_volumetricLightingVertexData;
long m_memoryTransferredThisFrame;
std::vector<draw_call_info> m_draw_calls;
bool m_draw_call_logging_enabled;
bool m_draw_call_log_used;
bool m_first_frame;
std::mutex m_streamerFenceMutex;
bool m_streamerComplete;
void balanceVBOMemory(long &memoryRemaining, long &memoryRemainingThisFrame);
void primeVBO(KRVBOData *vbo_data);
};
#endif
//
// KRMeshManager.h
// 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.
//
#ifndef KRMESHMANAGER_H
#define KRMESHMANAGER_H
#include "KREngine-common.h"
#include "KRContextObject.h"
#include "KRDataBlock.h"
#include "KRNode.h"
class KRContext;
class KRMesh;
class KRMeshManager : public KRContextObject {
public:
static const int KRENGINE_MAX_VOLUMETRIC_PLANES=500;
static const int KRENGINE_MAX_RANDOM_PARTICLES=150000;
KRMeshManager(KRContext &context);
virtual ~KRMeshManager();
void startFrame(float deltaTime);
void endFrame(float deltaTime);
void firstFrame();
KRMesh *loadModel(const char *szName, KRDataBlock *pData);
std::vector<KRMesh *> getModel(const char *szName);
void addModel(KRMesh *model);
std::vector<std::string> getModelNames();
unordered_multimap<std::string, KRMesh *> &getModels();
class KRVBOData {
public:
typedef enum {
STREAMING,
CONSTANT,
TEMPORARY
} vbo_type;
KRVBOData();
KRVBOData(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t);
void init(KRMeshManager *manager, KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t);
~KRVBOData();
KRDataBlock *m_data;
KRDataBlock *m_index_data;
bool isVBOLoaded() { return m_is_vbo_loaded; }
bool isVBOReady() { return m_is_vbo_ready; }
void load();
void unload();
void bind();
// Disable copy constructors
KRVBOData(const KRVBOData& o) = delete;
KRVBOData& operator=(const KRVBOData& o) = delete;
long getSize() { return m_size; }
void resetPoolExpiry(float lodCoverage);
long getLastFrameUsed() { return m_last_frame_used; }
vbo_type getType() { return m_type; }
float getStreamPriority();
void _swapHandles();
private:
KRMeshManager *m_manager;
int m_vertex_attrib_flags;
GLuint m_vbo_handle;
GLuint m_vbo_handle_indexes;
GLuint m_vao_handle;
GLsizeiptr m_size;
long m_last_frame_used;
float m_last_frame_max_lod_coverage;
vbo_type m_type;
bool m_static_vbo;
bool m_is_vbo_loaded;
bool m_is_vbo_ready;
};
void bindVBO(KRVBOData *vbo_data, float lodCoverage);
void bindVBO(KRDataBlock &data, KRDataBlock &index_data, int vertex_attrib_flags, bool static_vbo, float lodCoverage);
void unbindVBO();
long getMemUsed();
long getMemActive();
static void configureAttribs(__int32_t attributes);
typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vector3D;
typedef struct {
GLfloat u;
GLfloat v;
} TexCoord;
typedef struct {
Vector3D vertex;
TexCoord uva;
} RandomParticleVertexData;
typedef struct {
Vector3D vertex;
} VolumetricLightingVertexData;
KRDataBlock &getRandomParticles();
KRDataBlock &getVolumetricLightingVertexes();
long getMemoryTransferedThisFrame();
int getActiveVBOCount();
struct draw_call_info {
KRNode::RenderPass pass;
char object_name[256];
char material_name[256];
int vertex_count;
};
void log_draw_call(KRNode::RenderPass pass, const std::string &object_name, const std::string &material_name, int vertex_count);
std::vector<draw_call_info> getDrawCalls();
KRVBOData KRENGINE_VBO_DATA_3D_CUBE_VERTICES;
KRVBOData KRENGINE_VBO_DATA_2D_SQUARE_VERTICES;
void doStreaming(long &memoryRemaining, long &memoryRemainingThisFrame);
private:
KRDataBlock KRENGINE_VBO_3D_CUBE_VERTICES, KRENGINE_VBO_3D_CUBE_INDEXES;
__int32_t KRENGINE_VBO_3D_CUBE_ATTRIBS;
KRDataBlock KRENGINE_VBO_2D_SQUARE_VERTICES, KRENGINE_VBO_2D_SQUARE_INDEXES;
__int32_t KRENGINE_VBO_2D_SQUARE_ATTRIBS;
unordered_multimap<std::string, KRMesh *> m_models; // Multiple models with the same name/key may be inserted, representing multiple LOD levels of the model
long m_vboMemUsed;
KRVBOData *m_currentVBO;
unordered_map<KRDataBlock *, KRVBOData *> m_vbosActive;
std::vector<std::pair<float, KRVBOData *> > m_activeVBOs_streamer;
std::vector<std::pair<float, KRVBOData *> > m_activeVBOs_streamer_copy;
KRDataBlock m_randomParticleVertexData;
KRDataBlock m_volumetricLightingVertexData;
long m_memoryTransferredThisFrame;
std::vector<draw_call_info> m_draw_calls;
bool m_draw_call_logging_enabled;
bool m_draw_call_log_used;
bool m_first_frame;
std::mutex m_streamerFenceMutex;
bool m_streamerComplete;
void balanceVBOMemory(long &memoryRemaining, long &memoryRemainingThisFrame);
void primeVBO(KRVBOData *vbo_data);
};
#endif

View File

@@ -1,63 +1,63 @@
//
// KRMeshQuad.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.
//
#include "KRMeshQuad.h"
KRMeshQuad::KRMeshQuad(KRContext &context) : KRMesh(context, "__quad")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3(-1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3(1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3(-1.0f, 1.0f, 0.0f));
mi.vertices.push_back(Vector3(1.0f, 1.0f, 0.0f));
mi.uva.push_back(Vector2(0.0f, 0.0f));
mi.uva.push_back(Vector2(1.0f, 0.0f));
mi.uva.push_back(Vector2(0.0f, 1.0f));
mi.uva.push_back(Vector2(1.0f, 1.0f));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshQuad::~KRMeshQuad()
{
}
//
// KRMeshQuad.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.
//
#include "KRMeshQuad.h"
KRMeshQuad::KRMeshQuad(KRContext &context) : KRMesh(context, "__quad")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3::Create(-1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(-1.0f, 1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(1.0f, 1.0f, 0.0f));
mi.uva.push_back(Vector2::Create(0.0f, 0.0f));
mi.uva.push_back(Vector2::Create(1.0f, 0.0f));
mi.uva.push_back(Vector2::Create(0.0f, 1.0f));
mi.uva.push_back(Vector2::Create(1.0f, 1.0f));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshQuad::~KRMeshQuad()
{
}

View File

@@ -1,135 +1,135 @@
//
// KRMeshSphere.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.
//
#include "KRMeshSphere.h"
KRMeshSphere::KRMeshSphere(KRContext &context) : KRMesh(context, "__sphere")
{
m_constant = true;
KRMesh::mesh_info mi;
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3;
int facet_count = pow(4, iterations) * 8;
class Facet3 {
public:
Facet3() {
}
~Facet3() {
}
Vector3 p1;
Vector3 p2;
Vector3 p3;
};
std::vector<Facet3> f = std::vector<Facet3>(facet_count);
int i,it;
float a;
Vector3 p[6] = {
Vector3(0,0,1),
Vector3(0,0,-1),
Vector3(-1,-1,0),
Vector3(1,-1,0),
Vector3(1,1,0),
Vector3(-1,1,0)
};
Vector3 pa,pb,pc;
int nt = 0,ntold;
/* Create the level 0 object */
a = 1 / sqrt(2.0);
for (i=0;i<6;i++) {
p[i].x *= a;
p[i].y *= a;
}
f[0].p1 = p[0]; f[0].p2 = p[3]; f[0].p3 = p[4];
f[1].p1 = p[0]; f[1].p2 = p[4]; f[1].p3 = p[5];
f[2].p1 = p[0]; f[2].p2 = p[5]; f[2].p3 = p[2];
f[3].p1 = p[0]; f[3].p2 = p[2]; f[3].p3 = p[3];
f[4].p1 = p[1]; f[4].p2 = p[4]; f[4].p3 = p[3];
f[5].p1 = p[1]; f[5].p2 = p[5]; f[5].p3 = p[4];
f[6].p1 = p[1]; f[6].p2 = p[2]; f[6].p3 = p[5];
f[7].p1 = p[1]; f[7].p2 = p[3]; f[7].p3 = p[2];
nt = 8;
/* Bisect each edge and move to the surface of a unit sphere */
for (it=0;it<iterations;it++) {
ntold = nt;
for (i=0;i<ntold;i++) {
pa.x = (f[i].p1.x + f[i].p2.x) / 2;
pa.y = (f[i].p1.y + f[i].p2.y) / 2;
pa.z = (f[i].p1.z + f[i].p2.z) / 2;
pb.x = (f[i].p2.x + f[i].p3.x) / 2;
pb.y = (f[i].p2.y + f[i].p3.y) / 2;
pb.z = (f[i].p2.z + f[i].p3.z) / 2;
pc.x = (f[i].p3.x + f[i].p1.x) / 2;
pc.y = (f[i].p3.y + f[i].p1.y) / 2;
pc.z = (f[i].p3.z + f[i].p1.z) / 2;
pa.normalize();
pb.normalize();
pc.normalize();
f[nt].p1 = f[i].p1; f[nt].p2 = pa; f[nt].p3 = pc; nt++;
f[nt].p1 = pa; f[nt].p2 = f[i].p2; f[nt].p3 = pb; nt++;
f[nt].p1 = pb; f[nt].p2 = f[i].p3; f[nt].p3 = pc; nt++;
f[i].p1 = pa;
f[i].p2 = pb;
f[i].p3 = pc;
}
}
for(int facet_index=0; facet_index < facet_count; facet_index++) {
mi.vertices.push_back(f[facet_index].p1);
mi.vertices.push_back(f[facet_index].p2);
mi.vertices.push_back(f[facet_index].p3);
}
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_TRIANGLES;
LoadData(mi, true, true);
}
KRMeshSphere::~KRMeshSphere()
{
}
//
// KRMeshSphere.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.
//
#include "KRMeshSphere.h"
KRMeshSphere::KRMeshSphere(KRContext &context) : KRMesh(context, "__sphere")
{
m_constant = true;
KRMesh::mesh_info mi;
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3;
int facet_count = pow(4, iterations) * 8;
class Facet3 {
public:
Facet3() {
}
~Facet3() {
}
Vector3 p1;
Vector3 p2;
Vector3 p3;
};
std::vector<Facet3> f = std::vector<Facet3>(facet_count);
int i,it;
float a;
Vector3 p[6] = {
Vector3::Create(0,0,1),
Vector3::Create(0,0,-1),
Vector3::Create(-1,-1,0),
Vector3::Create(1,-1,0),
Vector3::Create(1,1,0),
Vector3::Create(-1,1,0)
};
Vector3 pa,pb,pc;
int nt = 0,ntold;
/* Create the level 0 object */
a = 1 / sqrt(2.0);
for (i=0;i<6;i++) {
p[i].x *= a;
p[i].y *= a;
}
f[0].p1 = p[0]; f[0].p2 = p[3]; f[0].p3 = p[4];
f[1].p1 = p[0]; f[1].p2 = p[4]; f[1].p3 = p[5];
f[2].p1 = p[0]; f[2].p2 = p[5]; f[2].p3 = p[2];
f[3].p1 = p[0]; f[3].p2 = p[2]; f[3].p3 = p[3];
f[4].p1 = p[1]; f[4].p2 = p[4]; f[4].p3 = p[3];
f[5].p1 = p[1]; f[5].p2 = p[5]; f[5].p3 = p[4];
f[6].p1 = p[1]; f[6].p2 = p[2]; f[6].p3 = p[5];
f[7].p1 = p[1]; f[7].p2 = p[3]; f[7].p3 = p[2];
nt = 8;
/* Bisect each edge and move to the surface of a unit sphere */
for (it=0;it<iterations;it++) {
ntold = nt;
for (i=0;i<ntold;i++) {
pa.x = (f[i].p1.x + f[i].p2.x) / 2;
pa.y = (f[i].p1.y + f[i].p2.y) / 2;
pa.z = (f[i].p1.z + f[i].p2.z) / 2;
pb.x = (f[i].p2.x + f[i].p3.x) / 2;
pb.y = (f[i].p2.y + f[i].p3.y) / 2;
pb.z = (f[i].p2.z + f[i].p3.z) / 2;
pc.x = (f[i].p3.x + f[i].p1.x) / 2;
pc.y = (f[i].p3.y + f[i].p1.y) / 2;
pc.z = (f[i].p3.z + f[i].p1.z) / 2;
pa.normalize();
pb.normalize();
pc.normalize();
f[nt].p1 = f[i].p1; f[nt].p2 = pa; f[nt].p3 = pc; nt++;
f[nt].p1 = pa; f[nt].p2 = f[i].p2; f[nt].p3 = pb; nt++;
f[nt].p1 = pb; f[nt].p2 = f[i].p3; f[nt].p3 = pc; nt++;
f[i].p1 = pa;
f[i].p2 = pb;
f[i].p3 = pc;
}
}
for(int facet_index=0; facet_index < facet_count; facet_index++) {
mi.vertices.push_back(f[facet_index].p1);
mi.vertices.push_back(f[facet_index].p2);
mi.vertices.push_back(f[facet_index].p3);
}
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back(mi.vertices.size());
mi.material_names.push_back("");
mi.format = KRENGINE_MODEL_FORMAT_TRIANGLES;
LoadData(mi, true, true);
}
KRMeshSphere::~KRMeshSphere()
{
}

View File

@@ -1,263 +1,263 @@
//
// KRModel.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.
//
#include "KREngine-common.h"
#include "KRModel.h"
#include "KRContext.h"
#include "KRMesh.h"
KRModel::KRModel(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map, float lod_min_coverage, bool receives_shadow, bool faces_camera, Vector3 rim_color, float rim_power) : KRNode(scene, instance_name) {
m_lightMap = light_map;
m_pLightMap = NULL;
m_model_name = model_name;
m_min_lod_coverage = lod_min_coverage;
m_receivesShadow = receives_shadow;
m_faces_camera = faces_camera;
m_rim_color = rim_color;
m_rim_power = rim_power;
m_boundsCachedMat.c[0] = -1.0f;
m_boundsCachedMat.c[1] = -1.0f;
m_boundsCachedMat.c[2] = -1.0f;
m_boundsCachedMat.c[3] = -1.0f;
m_boundsCachedMat.c[4] = -1.0f;
m_boundsCachedMat.c[5] = -1.0f;
m_boundsCachedMat.c[6] = -1.0f;
m_boundsCachedMat.c[7] = -1.0f;
m_boundsCachedMat.c[8] = -1.0f;
m_boundsCachedMat.c[9] = -1.0f;
m_boundsCachedMat.c[10] = -1.0f;
m_boundsCachedMat.c[11] = -1.0f;
m_boundsCachedMat.c[12] = -1.0f;
m_boundsCachedMat.c[13] = -1.0f;
m_boundsCachedMat.c[14] = -1.0f;
m_boundsCachedMat.c[15] = -1.0f;
}
KRModel::~KRModel() {
}
std::string KRModel::getElementName() {
return "model";
}
tinyxml2::XMLElement *KRModel::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("mesh", m_model_name.c_str());
e->SetAttribute("light_map", m_lightMap.c_str());
e->SetAttribute("lod_min_coverage", m_min_lod_coverage);
e->SetAttribute("receives_shadow", m_receivesShadow ? "true" : "false");
e->SetAttribute("faces_camera", m_faces_camera ? "true" : "false");
kraken::setXMLAttribute("rim_color", e, m_rim_color, Vector3::Zero());
e->SetAttribute("rim_power", m_rim_power);
return e;
}
void KRModel::setRimColor(const Vector3 &rim_color)
{
m_rim_color = rim_color;
}
void KRModel::setRimPower(float rim_power)
{
m_rim_power = rim_power;
}
Vector3 KRModel::getRimColor()
{
return m_rim_color;
}
float KRModel::getRimPower()
{
return m_rim_power;
}
void KRModel::setLightMap(const std::string &name)
{
m_lightMap = name;
m_pLightMap = NULL;
}
std::string KRModel::getLightMap()
{
return m_lightMap;
}
void KRModel::loadModel() {
if(m_models.size() == 0) {
std::vector<KRMesh *> models = m_pContext->getMeshManager()->getModel(m_model_name.c_str()); // The model manager returns the LOD levels in sorted order, with the highest detail first
unordered_map<KRMesh *, std::vector<KRBone *> > bones;
if(models.size() > 0) {
bool all_bones_found = true;
for(std::vector<KRMesh *>::iterator model_itr = models.begin(); model_itr != models.end(); model_itr++) {
KRMesh *model = *model_itr;
std::vector<KRBone *> model_bones;
int bone_count = model->getBoneCount();
for(int bone_index=0; bone_index < bone_count; bone_index++) {
KRBone *matching_bone = dynamic_cast<KRBone *>(getScene().getRootNode()->find<KRNode>(model->getBoneName(bone_index)));
if(matching_bone) {
model_bones.push_back(matching_bone);
} else {
all_bones_found = false; // Reject when there are any missing bones or multiple matches
}
}
bones[model] = model_bones;
}
if(all_bones_found) {
m_models = models;
m_bones = bones;
getScene().notify_sceneGraphModify(this);
}
invalidateBounds();
}
}
}
void KRModel::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible >= LOD_VISIBILITY_PRESTREAM && renderPass == KRNode::RENDER_PASS_PRESTREAM) {
preStream(viewport);
}
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass != KRNode::RENDER_PASS_DEFERRED_LIGHTS && renderPass != KRNode::RENDER_PASS_ADDITIVE_PARTICLES && renderPass != KRNode::RENDER_PASS_PARTICLE_OCCLUSION && renderPass != KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE && renderPass != KRNode::RENDER_PASS_GENERATE_SHADOWMAPS && renderPass != KRNode::RENDER_PASS_PRESTREAM) {
loadModel();
if(m_models.size() > 0) {
// Don't render meshes on second pass of the deferred lighting renderer, as only lights will be applied
/*
float lod_coverage = 0.0f;
if(m_models.size() > 1) {
lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling
} else if(viewport.visible(getBounds())) {
lod_coverage = 1.0f;
}
*/
float lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling
if(lod_coverage > m_min_lod_coverage) {
// ---===--- Select the best LOD model based on screen coverage ---===---
std::vector<KRMesh *>::iterator itr=m_models.begin();
KRMesh *pModel = *itr++;
while(itr != m_models.end()) {
KRMesh *pLODModel = *itr++;
if((float)pLODModel->getLODCoverage() / 100.0f > lod_coverage && pLODModel->getLODCoverage() < pModel->getLODCoverage()) {
pModel = pLODModel;
} else {
break;
}
}
if(m_pLightMap == NULL && m_lightMap.size()) {
m_pLightMap = getContext().getTextureManager()->getTexture(m_lightMap);
}
if(m_pLightMap && pCamera->settings.bEnableLightMap && renderPass != RENDER_PASS_SHADOWMAP && renderPass != RENDER_PASS_GENERATE_SHADOWMAPS) {
m_pContext->getTextureManager()->selectTexture(5, m_pLightMap, lod_coverage, KRTexture::TEXTURE_USAGE_LIGHT_MAP);
}
Matrix4 matModel = getModelMatrix();
if(m_faces_camera) {
Vector3 model_center = Matrix4::Dot(matModel, Vector3::Zero());
Vector3 camera_pos = viewport.getCameraPosition();
matModel = Quaternion(Vector3::Forward(), Vector3::Normalize(camera_pos - model_center)).rotationMatrix() * matModel;
}
pModel->render(getName(), pCamera, point_lights, directional_lights, spot_lights, viewport, matModel, m_pLightMap, renderPass, m_bones[pModel], m_rim_color, m_rim_power, lod_coverage);
}
}
}
}
void KRModel::preStream(const KRViewport &viewport)
{
loadModel();
float lod_coverage = viewport.coverage(getBounds());
for(auto itr = m_models.begin(); itr != m_models.end(); itr++) {
(*itr)->preStream(lod_coverage);
}
if(m_pLightMap == NULL && m_lightMap.size()) {
m_pLightMap = getContext().getTextureManager()->getTexture(m_lightMap);
}
if(m_pLightMap) {
m_pLightMap->resetPoolExpiry(lod_coverage, KRTexture::TEXTURE_USAGE_LIGHT_MAP);
}
}
kraken_stream_level KRModel::getStreamLevel(const KRViewport &viewport)
{
kraken_stream_level stream_level = KRNode::getStreamLevel(viewport);
loadModel();
for(auto itr = m_models.begin(); itr != m_models.end(); itr++) {
stream_level = KRMIN(stream_level, (*itr)->getStreamLevel());
}
return stream_level;
}
AABB KRModel::getBounds() {
loadModel();
if(m_models.size() > 0) {
if(m_faces_camera) {
AABB normal_bounds = AABB(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
float max_dimension = normal_bounds.longest_radius();
return AABB(normal_bounds.center()-Vector3(max_dimension), normal_bounds.center() + Vector3(max_dimension));
} else {
if(!(m_boundsCachedMat == getModelMatrix())) {
m_boundsCachedMat = getModelMatrix();
m_boundsCached = AABB(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
}
return m_boundsCached;
}
} else {
return AABB::Infinite();
}
}
//
// KRModel.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.
//
#include "KREngine-common.h"
#include "KRModel.h"
#include "KRContext.h"
#include "KRMesh.h"
KRModel::KRModel(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map, float lod_min_coverage, bool receives_shadow, bool faces_camera, Vector3 rim_color, float rim_power) : KRNode(scene, instance_name) {
m_lightMap = light_map;
m_pLightMap = NULL;
m_model_name = model_name;
m_min_lod_coverage = lod_min_coverage;
m_receivesShadow = receives_shadow;
m_faces_camera = faces_camera;
m_rim_color = rim_color;
m_rim_power = rim_power;
m_boundsCachedMat.c[0] = -1.0f;
m_boundsCachedMat.c[1] = -1.0f;
m_boundsCachedMat.c[2] = -1.0f;
m_boundsCachedMat.c[3] = -1.0f;
m_boundsCachedMat.c[4] = -1.0f;
m_boundsCachedMat.c[5] = -1.0f;
m_boundsCachedMat.c[6] = -1.0f;
m_boundsCachedMat.c[7] = -1.0f;
m_boundsCachedMat.c[8] = -1.0f;
m_boundsCachedMat.c[9] = -1.0f;
m_boundsCachedMat.c[10] = -1.0f;
m_boundsCachedMat.c[11] = -1.0f;
m_boundsCachedMat.c[12] = -1.0f;
m_boundsCachedMat.c[13] = -1.0f;
m_boundsCachedMat.c[14] = -1.0f;
m_boundsCachedMat.c[15] = -1.0f;
}
KRModel::~KRModel() {
}
std::string KRModel::getElementName() {
return "model";
}
tinyxml2::XMLElement *KRModel::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("mesh", m_model_name.c_str());
e->SetAttribute("light_map", m_lightMap.c_str());
e->SetAttribute("lod_min_coverage", m_min_lod_coverage);
e->SetAttribute("receives_shadow", m_receivesShadow ? "true" : "false");
e->SetAttribute("faces_camera", m_faces_camera ? "true" : "false");
kraken::setXMLAttribute("rim_color", e, m_rim_color, Vector3::Zero());
e->SetAttribute("rim_power", m_rim_power);
return e;
}
void KRModel::setRimColor(const Vector3 &rim_color)
{
m_rim_color = rim_color;
}
void KRModel::setRimPower(float rim_power)
{
m_rim_power = rim_power;
}
Vector3 KRModel::getRimColor()
{
return m_rim_color;
}
float KRModel::getRimPower()
{
return m_rim_power;
}
void KRModel::setLightMap(const std::string &name)
{
m_lightMap = name;
m_pLightMap = NULL;
}
std::string KRModel::getLightMap()
{
return m_lightMap;
}
void KRModel::loadModel() {
if(m_models.size() == 0) {
std::vector<KRMesh *> models = m_pContext->getMeshManager()->getModel(m_model_name.c_str()); // The model manager returns the LOD levels in sorted order, with the highest detail first
unordered_map<KRMesh *, std::vector<KRBone *> > bones;
if(models.size() > 0) {
bool all_bones_found = true;
for(std::vector<KRMesh *>::iterator model_itr = models.begin(); model_itr != models.end(); model_itr++) {
KRMesh *model = *model_itr;
std::vector<KRBone *> model_bones;
int bone_count = model->getBoneCount();
for(int bone_index=0; bone_index < bone_count; bone_index++) {
KRBone *matching_bone = dynamic_cast<KRBone *>(getScene().getRootNode()->find<KRNode>(model->getBoneName(bone_index)));
if(matching_bone) {
model_bones.push_back(matching_bone);
} else {
all_bones_found = false; // Reject when there are any missing bones or multiple matches
}
}
bones[model] = model_bones;
}
if(all_bones_found) {
m_models = models;
m_bones = bones;
getScene().notify_sceneGraphModify(this);
}
invalidateBounds();
}
}
}
void KRModel::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible >= LOD_VISIBILITY_PRESTREAM && renderPass == KRNode::RENDER_PASS_PRESTREAM) {
preStream(viewport);
}
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass != KRNode::RENDER_PASS_DEFERRED_LIGHTS && renderPass != KRNode::RENDER_PASS_ADDITIVE_PARTICLES && renderPass != KRNode::RENDER_PASS_PARTICLE_OCCLUSION && renderPass != KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE && renderPass != KRNode::RENDER_PASS_GENERATE_SHADOWMAPS && renderPass != KRNode::RENDER_PASS_PRESTREAM) {
loadModel();
if(m_models.size() > 0) {
// Don't render meshes on second pass of the deferred lighting renderer, as only lights will be applied
/*
float lod_coverage = 0.0f;
if(m_models.size() > 1) {
lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling
} else if(viewport.visible(getBounds())) {
lod_coverage = 1.0f;
}
*/
float lod_coverage = viewport.coverage(getBounds()); // This also checks the view frustrum culling
if(lod_coverage > m_min_lod_coverage) {
// ---===--- Select the best LOD model based on screen coverage ---===---
std::vector<KRMesh *>::iterator itr=m_models.begin();
KRMesh *pModel = *itr++;
while(itr != m_models.end()) {
KRMesh *pLODModel = *itr++;
if((float)pLODModel->getLODCoverage() / 100.0f > lod_coverage && pLODModel->getLODCoverage() < pModel->getLODCoverage()) {
pModel = pLODModel;
} else {
break;
}
}
if(m_pLightMap == NULL && m_lightMap.size()) {
m_pLightMap = getContext().getTextureManager()->getTexture(m_lightMap);
}
if(m_pLightMap && pCamera->settings.bEnableLightMap && renderPass != RENDER_PASS_SHADOWMAP && renderPass != RENDER_PASS_GENERATE_SHADOWMAPS) {
m_pContext->getTextureManager()->selectTexture(5, m_pLightMap, lod_coverage, KRTexture::TEXTURE_USAGE_LIGHT_MAP);
}
Matrix4 matModel = getModelMatrix();
if(m_faces_camera) {
Vector3 model_center = Matrix4::Dot(matModel, Vector3::Zero());
Vector3 camera_pos = viewport.getCameraPosition();
matModel = Quaternion::Create(Vector3::Forward(), Vector3::Normalize(camera_pos - model_center)).rotationMatrix() * matModel;
}
pModel->render(getName(), pCamera, point_lights, directional_lights, spot_lights, viewport, matModel, m_pLightMap, renderPass, m_bones[pModel], m_rim_color, m_rim_power, lod_coverage);
}
}
}
}
void KRModel::preStream(const KRViewport &viewport)
{
loadModel();
float lod_coverage = viewport.coverage(getBounds());
for(auto itr = m_models.begin(); itr != m_models.end(); itr++) {
(*itr)->preStream(lod_coverage);
}
if(m_pLightMap == NULL && m_lightMap.size()) {
m_pLightMap = getContext().getTextureManager()->getTexture(m_lightMap);
}
if(m_pLightMap) {
m_pLightMap->resetPoolExpiry(lod_coverage, KRTexture::TEXTURE_USAGE_LIGHT_MAP);
}
}
kraken_stream_level KRModel::getStreamLevel(const KRViewport &viewport)
{
kraken_stream_level stream_level = KRNode::getStreamLevel(viewport);
loadModel();
for(auto itr = m_models.begin(); itr != m_models.end(); itr++) {
stream_level = KRMIN(stream_level, (*itr)->getStreamLevel());
}
return stream_level;
}
AABB KRModel::getBounds() {
loadModel();
if(m_models.size() > 0) {
if(m_faces_camera) {
AABB normal_bounds = AABB::Create(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
float max_dimension = normal_bounds.longest_radius();
return AABB::Create(normal_bounds.center()-Vector3::Create(max_dimension), normal_bounds.center() + Vector3::Create(max_dimension));
} else {
if(!(m_boundsCachedMat == getModelMatrix())) {
m_boundsCachedMat = getModelMatrix();
m_boundsCached = AABB::Create(m_models[0]->getMinPoint(), m_models[0]->getMaxPoint(), getModelMatrix());
}
return m_boundsCached;
}
} else {
return AABB::Infinite();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,156 +1,156 @@
//
// KROctree.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
#include "KROctree.h"
#include "KRNode.h"
#include "KRCollider.h"
KROctree::KROctree()
{
m_pRootNode = NULL;
}
KROctree::~KROctree()
{
if(m_pRootNode) {
delete m_pRootNode;
}
}
void KROctree::add(KRNode *pNode)
{
AABB nodeBounds = pNode->getBounds();
if(nodeBounds == AABB::Zero()) {
// This item is not visible, don't add it to the octree or outer scene nodes
} else if(nodeBounds == AABB::Infinite()) {
// This item is infinitely large; we track it separately
m_outerSceneNodes.insert(pNode);
} else {
if(m_pRootNode == NULL) {
// First item inserted, create a node large enough to fit it
m_pRootNode = new KROctreeNode(NULL, nodeBounds);
m_pRootNode->add(pNode);
} else {
// Keep encapsulating the root node until the new root contains the inserted node
bool bInsideRoot = false;
while(!bInsideRoot) {
AABB rootBounds = m_pRootNode->getBounds();
Vector3 rootSize = rootBounds.size();
if(nodeBounds.min.x < rootBounds.min.x || nodeBounds.min.y < rootBounds.min.y || nodeBounds.min.z < rootBounds.min.z) {
m_pRootNode = new KROctreeNode(NULL, AABB(rootBounds.min - rootSize, rootBounds.max), 7, m_pRootNode);
} else if(nodeBounds.max.x > rootBounds.max.x || nodeBounds.max.y > rootBounds.max.y || nodeBounds.max.z > rootBounds.max.z) {
m_pRootNode = new KROctreeNode(NULL, AABB(rootBounds.min, rootBounds.max + rootSize), 0, m_pRootNode);
} else {
bInsideRoot = true;
}
}
m_pRootNode->add(pNode);
}
}
}
void KROctree::remove(KRNode *pNode)
{
if(!m_outerSceneNodes.erase(pNode)) {
if(m_pRootNode) {
pNode->removeFromOctreeNodes();
}
}
shrink();
}
void KROctree::update(KRNode *pNode)
{
// TODO: This may be more efficient as an incremental operation rather than removing and re-adding the node
remove(pNode);
add(pNode);
shrink();
}
void KROctree::shrink()
{
if(m_pRootNode) {
while(m_pRootNode->canShrinkRoot()) {
KROctreeNode *newRoot = m_pRootNode->stripChild();
delete m_pRootNode;
m_pRootNode = newRoot;
if(m_pRootNode == NULL) return;
}
}
}
KROctreeNode *KROctree::getRootNode()
{
return m_pRootNode;
}
std::set<KRNode *> &KROctree::getOuterSceneNodes()
{
return m_outerSceneNodes;
}
bool KROctree::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
std::vector<KRCollider *> outer_colliders;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
outer_colliders.push_back(collider);
}
}
for(std::vector<KRCollider *>::iterator itr=outer_colliders.begin(); itr != outer_colliders.end(); itr++) {
if((*itr)->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
if(m_pRootNode) {
if(m_pRootNode->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}
bool KROctree::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
if(collider->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
}
if(m_pRootNode) {
if(m_pRootNode->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}
bool KROctree::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
std::vector<KRCollider *> outer_colliders;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
outer_colliders.push_back(collider);
}
}
for(std::vector<KRCollider *>::iterator itr=outer_colliders.begin(); itr != outer_colliders.end(); itr++) {
if((*itr)->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
if(m_pRootNode) {
if(m_pRootNode->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}
//
// KROctree.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
#include "KROctree.h"
#include "KRNode.h"
#include "KRCollider.h"
KROctree::KROctree()
{
m_pRootNode = NULL;
}
KROctree::~KROctree()
{
if(m_pRootNode) {
delete m_pRootNode;
}
}
void KROctree::add(KRNode *pNode)
{
AABB nodeBounds = pNode->getBounds();
if(nodeBounds == AABB::Zero()) {
// This item is not visible, don't add it to the octree or outer scene nodes
} else if(nodeBounds == AABB::Infinite()) {
// This item is infinitely large; we track it separately
m_outerSceneNodes.insert(pNode);
} else {
if(m_pRootNode == NULL) {
// First item inserted, create a node large enough to fit it
m_pRootNode = new KROctreeNode(NULL, nodeBounds);
m_pRootNode->add(pNode);
} else {
// Keep encapsulating the root node until the new root contains the inserted node
bool bInsideRoot = false;
while(!bInsideRoot) {
AABB rootBounds = m_pRootNode->getBounds();
Vector3 rootSize = rootBounds.size();
if(nodeBounds.min.x < rootBounds.min.x || nodeBounds.min.y < rootBounds.min.y || nodeBounds.min.z < rootBounds.min.z) {
m_pRootNode = new KROctreeNode(NULL, AABB::Create(rootBounds.min - rootSize, rootBounds.max), 7, m_pRootNode);
} else if(nodeBounds.max.x > rootBounds.max.x || nodeBounds.max.y > rootBounds.max.y || nodeBounds.max.z > rootBounds.max.z) {
m_pRootNode = new KROctreeNode(NULL, AABB::Create(rootBounds.min, rootBounds.max + rootSize), 0, m_pRootNode);
} else {
bInsideRoot = true;
}
}
m_pRootNode->add(pNode);
}
}
}
void KROctree::remove(KRNode *pNode)
{
if(!m_outerSceneNodes.erase(pNode)) {
if(m_pRootNode) {
pNode->removeFromOctreeNodes();
}
}
shrink();
}
void KROctree::update(KRNode *pNode)
{
// TODO: This may be more efficient as an incremental operation rather than removing and re-adding the node
remove(pNode);
add(pNode);
shrink();
}
void KROctree::shrink()
{
if(m_pRootNode) {
while(m_pRootNode->canShrinkRoot()) {
KROctreeNode *newRoot = m_pRootNode->stripChild();
delete m_pRootNode;
m_pRootNode = newRoot;
if(m_pRootNode == NULL) return;
}
}
}
KROctreeNode *KROctree::getRootNode()
{
return m_pRootNode;
}
std::set<KRNode *> &KROctree::getOuterSceneNodes()
{
return m_outerSceneNodes;
}
bool KROctree::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
std::vector<KRCollider *> outer_colliders;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
outer_colliders.push_back(collider);
}
}
for(std::vector<KRCollider *>::iterator itr=outer_colliders.begin(); itr != outer_colliders.end(); itr++) {
if((*itr)->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
if(m_pRootNode) {
if(m_pRootNode->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}
bool KROctree::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
if(collider->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
}
if(m_pRootNode) {
if(m_pRootNode->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}
bool KROctree::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
std::vector<KRCollider *> outer_colliders;
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
if(collider) {
outer_colliders.push_back(collider);
}
}
for(std::vector<KRCollider *>::iterator itr=outer_colliders.begin(); itr != outer_colliders.end(); itr++) {
if((*itr)->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
if(m_pRootNode) {
if(m_pRootNode->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
return hit_found;
}

View File

@@ -1,290 +1,290 @@
//
// KROctreeNode.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KROctreeNode.h"
#include "KRNode.h"
#include "KRCollider.h"
KROctreeNode::KROctreeNode(KROctreeNode *parent, const AABB &bounds) : m_bounds(bounds)
{
m_parent = parent;
for(int i=0; i<8; i++) m_children[i] = NULL;
m_occlusionQuery = 0;
m_occlusionTested = false;
m_activeQuery = false;
}
KROctreeNode::KROctreeNode(KROctreeNode *parent, const AABB &bounds, int iChild, KROctreeNode *pChild) : m_bounds(bounds)
{
// This constructor is used when expanding the octree and replacing the root node with a new root that encapsulates it
m_parent = parent;
for(int i=0; i<8; i++) m_children[i] = NULL;
m_children[iChild] = pChild;
pChild->m_parent = this;
m_occlusionQuery = 0;
m_occlusionTested = false;
m_activeQuery = false;
}
KROctreeNode::~KROctreeNode()
{
for(int i=0; i<8; i++) {
if(m_children[i] != NULL) {
delete m_children[i];
}
}
if(m_occlusionTested) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
}
}
void KROctreeNode::beginOcclusionQuery()
{
if(!m_occlusionTested){
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery));
#if TARGET_OS_IPHONE
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery));
#else
GLDEBUG(glBeginQuery(GL_SAMPLES_PASSED, m_occlusionQuery));
#endif
m_occlusionTested = true;
m_activeQuery = true;
}
}
void KROctreeNode::endOcclusionQuery()
{
if(m_activeQuery) {
// Only end a query if we started one
#if TARGET_OS_IPHONE
GLDEBUG(glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT));
#else
GLDEBUG(glEndQuery(GL_SAMPLES_PASSED));
#endif
}
}
AABB KROctreeNode::getBounds()
{
return m_bounds;
}
void KROctreeNode::add(KRNode *pNode)
{
int iChild = getChildIndex(pNode);
if(iChild == -1) {
m_sceneNodes.insert(pNode);
pNode->addToOctreeNode(this);
} else {
if(m_children[iChild] == NULL) {
m_children[iChild] = new KROctreeNode(this, getChildBounds(iChild));
}
m_children[iChild]->add(pNode);
}
}
AABB KROctreeNode::getChildBounds(int iChild)
{
Vector3 center = m_bounds.center();
return AABB(
Vector3(
(iChild & 1) == 0 ? m_bounds.min.x : center.x,
(iChild & 2) == 0 ? m_bounds.min.y : center.y,
(iChild & 4) == 0 ? m_bounds.min.z : center.z),
Vector3(
(iChild & 1) == 0 ? center.x : m_bounds.max.x,
(iChild & 2) == 0 ? center.y : m_bounds.max.y,
(iChild & 4) == 0 ? center.z : m_bounds.max.z)
);
}
int KROctreeNode::getChildIndex(KRNode *pNode)
{
for(int iChild=0; iChild < 8; iChild++) {
if(getChildBounds(iChild).contains(pNode->getBounds())) {
return iChild;
}
}
return -1;
}
void KROctreeNode::trim()
{
for(int iChild = 0; iChild < 8; iChild++) {
if(m_children[iChild]) {
if(m_children[iChild]->isEmpty()) {
delete m_children[iChild];
m_children[iChild] = NULL;
}
}
}
}
void KROctreeNode::remove(KRNode *pNode)
{
m_sceneNodes.erase(pNode);
}
void KROctreeNode::update(KRNode *pNode)
{
}
bool KROctreeNode::isEmpty() const
{
for(int i=0; i<8; i++) {
if(m_children[i]) {
return false;
}
}
return m_sceneNodes.empty();
}
bool KROctreeNode::canShrinkRoot() const
{
int cChildren = 0;
for(int i=0; i<8; i++) {
if(m_children[i]) {
cChildren++;
}
}
return cChildren <= 1 && m_sceneNodes.empty();
}
KROctreeNode *KROctreeNode::stripChild()
{
// Return the first found child and update its reference to NULL so that the destructor will not free it. This is used for shrinking the octree
// NOTE: The caller of this function will be responsible for freeing the child object. It is also possible to return a NULL
for(int i=0; i<8; i++) {
if(m_children[i]) {
KROctreeNode *child = m_children[i];
child->m_parent = NULL;
m_children[i] = NULL;
return child;
}
}
return NULL;
}
KROctreeNode *KROctreeNode::getParent()
{
return m_parent;
}
KROctreeNode **KROctreeNode::getChildren()
{
return m_children;
}
std::set<KRNode *> &KROctreeNode::getSceneNodes()
{
return m_sceneNodes;
}
bool KROctreeNode::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
if(hitinfo.didHit() && v1 != hitinfo.getPosition()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = lineCast(v0, hitinfo.getPosition(), hitinfo, layer_mask);
} else {
if(getBounds().intersectsLine(v0, v1)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->lineCast(v0, v1, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
}
return hit_found;
}
bool KROctreeNode::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
if(hitinfo.didHit()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = lineCast(v0, hitinfo.getPosition(), hitinfo, layer_mask); // Note: This is purposefully lineCast as opposed to RayCast
} else {
if(getBounds().intersectsRay(v0, dir)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->rayCast(v0, dir, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
}
return hit_found;
}
bool KROctreeNode::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
/*
// FINDME, TODO - Adapt this optimization to work with sphereCasts
if(hitinfo.didHit() && v1 != hitinfo.getPosition()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = sphereCast(v0, hitinfo.getPosition(), radius, hitinfo, layer_mask);
} else {
*/
AABB swept_bounds = AABB(Vector3(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius), Vector3(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius));
// FINDME, TODO - Investigate AABB - swept sphere intersections or OBB - AABB intersections: "if(getBounds().intersectsSweptSphere(v0, v1, radius)) {"
if(getBounds().intersects(swept_bounds)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->sphereCast(v0, v1, radius, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
// }
return hit_found;
}
//
// KROctreeNode.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KROctreeNode.h"
#include "KRNode.h"
#include "KRCollider.h"
KROctreeNode::KROctreeNode(KROctreeNode *parent, const AABB &bounds) : m_bounds(bounds)
{
m_parent = parent;
for(int i=0; i<8; i++) m_children[i] = NULL;
m_occlusionQuery = 0;
m_occlusionTested = false;
m_activeQuery = false;
}
KROctreeNode::KROctreeNode(KROctreeNode *parent, const AABB &bounds, int iChild, KROctreeNode *pChild) : m_bounds(bounds)
{
// This constructor is used when expanding the octree and replacing the root node with a new root that encapsulates it
m_parent = parent;
for(int i=0; i<8; i++) m_children[i] = NULL;
m_children[iChild] = pChild;
pChild->m_parent = this;
m_occlusionQuery = 0;
m_occlusionTested = false;
m_activeQuery = false;
}
KROctreeNode::~KROctreeNode()
{
for(int i=0; i<8; i++) {
if(m_children[i] != NULL) {
delete m_children[i];
}
}
if(m_occlusionTested) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
}
}
void KROctreeNode::beginOcclusionQuery()
{
if(!m_occlusionTested){
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery));
#if TARGET_OS_IPHONE
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery));
#else
GLDEBUG(glBeginQuery(GL_SAMPLES_PASSED, m_occlusionQuery));
#endif
m_occlusionTested = true;
m_activeQuery = true;
}
}
void KROctreeNode::endOcclusionQuery()
{
if(m_activeQuery) {
// Only end a query if we started one
#if TARGET_OS_IPHONE
GLDEBUG(glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT));
#else
GLDEBUG(glEndQuery(GL_SAMPLES_PASSED));
#endif
}
}
AABB KROctreeNode::getBounds()
{
return m_bounds;
}
void KROctreeNode::add(KRNode *pNode)
{
int iChild = getChildIndex(pNode);
if(iChild == -1) {
m_sceneNodes.insert(pNode);
pNode->addToOctreeNode(this);
} else {
if(m_children[iChild] == NULL) {
m_children[iChild] = new KROctreeNode(this, getChildBounds(iChild));
}
m_children[iChild]->add(pNode);
}
}
AABB KROctreeNode::getChildBounds(int iChild)
{
Vector3 center = m_bounds.center();
return AABB::Create(
Vector3::Create(
(iChild & 1) == 0 ? m_bounds.min.x : center.x,
(iChild & 2) == 0 ? m_bounds.min.y : center.y,
(iChild & 4) == 0 ? m_bounds.min.z : center.z),
Vector3::Create(
(iChild & 1) == 0 ? center.x : m_bounds.max.x,
(iChild & 2) == 0 ? center.y : m_bounds.max.y,
(iChild & 4) == 0 ? center.z : m_bounds.max.z)
);
}
int KROctreeNode::getChildIndex(KRNode *pNode)
{
for(int iChild=0; iChild < 8; iChild++) {
if(getChildBounds(iChild).contains(pNode->getBounds())) {
return iChild;
}
}
return -1;
}
void KROctreeNode::trim()
{
for(int iChild = 0; iChild < 8; iChild++) {
if(m_children[iChild]) {
if(m_children[iChild]->isEmpty()) {
delete m_children[iChild];
m_children[iChild] = NULL;
}
}
}
}
void KROctreeNode::remove(KRNode *pNode)
{
m_sceneNodes.erase(pNode);
}
void KROctreeNode::update(KRNode *pNode)
{
}
bool KROctreeNode::isEmpty() const
{
for(int i=0; i<8; i++) {
if(m_children[i]) {
return false;
}
}
return m_sceneNodes.empty();
}
bool KROctreeNode::canShrinkRoot() const
{
int cChildren = 0;
for(int i=0; i<8; i++) {
if(m_children[i]) {
cChildren++;
}
}
return cChildren <= 1 && m_sceneNodes.empty();
}
KROctreeNode *KROctreeNode::stripChild()
{
// Return the first found child and update its reference to NULL so that the destructor will not free it. This is used for shrinking the octree
// NOTE: The caller of this function will be responsible for freeing the child object. It is also possible to return a NULL
for(int i=0; i<8; i++) {
if(m_children[i]) {
KROctreeNode *child = m_children[i];
child->m_parent = NULL;
m_children[i] = NULL;
return child;
}
}
return NULL;
}
KROctreeNode *KROctreeNode::getParent()
{
return m_parent;
}
KROctreeNode **KROctreeNode::getChildren()
{
return m_children;
}
std::set<KRNode *> &KROctreeNode::getSceneNodes()
{
return m_sceneNodes;
}
bool KROctreeNode::lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
if(hitinfo.didHit() && v1 != hitinfo.getPosition()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = lineCast(v0, hitinfo.getPosition(), hitinfo, layer_mask);
} else {
if(getBounds().intersectsLine(v0, v1)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->lineCast(v0, v1, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->lineCast(v0, v1, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
}
return hit_found;
}
bool KROctreeNode::rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
if(hitinfo.didHit()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = lineCast(v0, hitinfo.getPosition(), hitinfo, layer_mask); // Note: This is purposefully lineCast as opposed to RayCast
} else {
if(getBounds().intersectsRay(v0, dir)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->rayCast(v0, dir, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->rayCast(v0, dir, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
}
return hit_found;
}
bool KROctreeNode::sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask)
{
bool hit_found = false;
/*
// FINDME, TODO - Adapt this optimization to work with sphereCasts
if(hitinfo.didHit() && v1 != hitinfo.getPosition()) {
// Optimization: If we already have a hit, only search for hits that are closer
hit_found = sphereCast(v0, hitinfo.getPosition(), radius, hitinfo, layer_mask);
} else {
*/
AABB swept_bounds = AABB::Create(Vector3::Create(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius), Vector3::Create(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius));
// FINDME, TODO - Investigate AABB - swept sphere intersections or OBB - AABB intersections: "if(getBounds().intersectsSweptSphere(v0, v1, radius)) {"
if(getBounds().intersects(swept_bounds)) {
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
if(collider) {
if(collider->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
}
}
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->sphereCast(v0, v1, radius, hitinfo, layer_mask)) {
hit_found = true;
}
}
}
}
// }
return hit_found;
}

View File

@@ -1,65 +1,65 @@
//
// KROctreeNode.h
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#ifndef KROCTREENODE_H
#define KROCTREENODE_H
#include "KREngine-common.h"
#include "public/hitinfo.h"
class KRNode;
class KROctreeNode {
public:
KROctreeNode(KROctreeNode *parent, const AABB &bounds);
KROctreeNode(KROctreeNode *parent, const AABB &bounds, int iChild, KROctreeNode *pChild);
~KROctreeNode();
KROctreeNode **getChildren();
std::set<KRNode *> &getSceneNodes();
void add(KRNode *pNode);
void remove(KRNode *pNode);
void update(KRNode *pNode);
AABB getBounds();
KROctreeNode *getParent();
void setChildNode(int iChild, KROctreeNode *pChild);
int getChildIndex(KRNode *pNode);
AABB getChildBounds(int iChild);
void trim();
bool isEmpty() const;
bool canShrinkRoot() const;
KROctreeNode *stripChild();
void beginOcclusionQuery();
void endOcclusionQuery();
GLuint m_occlusionQuery;
bool m_occlusionTested;
bool m_activeQuery;
bool lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask);
bool rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask);
bool sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask);
private:
AABB m_bounds;
KROctreeNode *m_parent;
KROctreeNode *m_children[8];
std::set<KRNode *>m_sceneNodes;
};
#endif /* defined(KROCTREENODE_H) */
//
// KROctreeNode.h
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-29.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#ifndef KROCTREENODE_H
#define KROCTREENODE_H
#include "KREngine-common.h"
#include "hitinfo.h"
class KRNode;
class KROctreeNode {
public:
KROctreeNode(KROctreeNode *parent, const AABB &bounds);
KROctreeNode(KROctreeNode *parent, const AABB &bounds, int iChild, KROctreeNode *pChild);
~KROctreeNode();
KROctreeNode **getChildren();
std::set<KRNode *> &getSceneNodes();
void add(KRNode *pNode);
void remove(KRNode *pNode);
void update(KRNode *pNode);
AABB getBounds();
KROctreeNode *getParent();
void setChildNode(int iChild, KROctreeNode *pChild);
int getChildIndex(KRNode *pNode);
AABB getChildBounds(int iChild);
void trim();
bool isEmpty() const;
bool canShrinkRoot() const;
KROctreeNode *stripChild();
void beginOcclusionQuery();
void endOcclusionQuery();
GLuint m_occlusionQuery;
bool m_occlusionTested;
bool m_activeQuery;
bool lineCast(const Vector3 &v0, const Vector3 &v1, HitInfo &hitinfo, unsigned int layer_mask);
bool rayCast(const Vector3 &v0, const Vector3 &dir, HitInfo &hitinfo, unsigned int layer_mask);
bool sphereCast(const Vector3 &v0, const Vector3 &v1, float radius, HitInfo &hitinfo, unsigned int layer_mask);
private:
AABB m_bounds;
KROctreeNode *m_parent;
KROctreeNode *m_children[8];
std::set<KRNode *>m_sceneNodes;
};
#endif /* defined(KROCTREENODE_H) */

View File

@@ -1,226 +1,226 @@
//
// KRPointLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRPointLight.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRStockGeometry.h"
KRPointLight::KRPointLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
m_sphereVertices = NULL;
m_cVertices = 0;
}
KRPointLight::~KRPointLight()
{
if(m_sphereVertices) {
delete m_sphereVertices;
m_cVertices = 0;
}
}
std::string KRPointLight::getElementName() {
return "point_light";
}
AABB KRPointLight::getBounds() {
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
if(influence_radius < m_flareOcclusionSize) {
influence_radius = m_flareOcclusionSize;
}
return AABB(Vector3(-influence_radius), Vector3(influence_radius), getModelMatrix());
}
void KRPointLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRLight::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && pCamera->settings.bShowDeferred;
if(renderPass == KRNode::RENDER_PASS_DEFERRED_LIGHTS || bVisualize) {
// Lights are rendered on the second pass of the deferred renderer
std::vector<KRPointLight *> this_light;
this_light.push_back(this);
Vector3 light_position = getLocalTranslation();
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
Matrix4 sphereModelMatrix = Matrix4();
sphereModelMatrix.scale(influence_radius);
sphereModelMatrix.translate(light_position.x, light_position.y, light_position.z);
if(viewport.visible(getBounds())) { // Cull out any lights not within the view frustrum
Vector3 view_light_position = Matrix4::Dot(viewport.getViewMatrix(), light_position);
bool bInsideLight = view_light_position.sqrMagnitude() <= (influence_radius + pCamera->settings.getPerspectiveNearZ()) * (influence_radius + pCamera->settings.getPerspectiveNearZ());
KRShader *pShader = getContext().getShaderManager()->getShader(bVisualize ? "visualize_overlay" : (bInsideLight ? "light_point_inside" : "light_point"), pCamera, this_light, std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 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, sphereModelMatrix, this_light, std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_INTENSITY, m_intensity * 0.01f);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_DECAY_START, getDecayStart());
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_CUTOFF, KRLIGHT_MIN_INFLUENCE);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_POSITION, light_position);
if(bVisualize) {
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
}
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
if(bInsideLight) {
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
// Render a full screen quad
m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
} else {
#if GL_OES_vertex_array_object
GLDEBUG(glBindVertexArrayOES(0));
#endif
m_pContext->getMeshManager()->configureAttribs(1 << KRMesh::KRENGINE_ATTRIB_VERTEX);
// Render sphere of light's influence
generateMesh();
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
GLDEBUG(glVertexAttribPointer(KRMesh::KRENGINE_ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, m_sphereVertices));
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, m_cVertices));
}
}
if(bVisualize) {
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
}
void KRPointLight::generateMesh() {
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3;
int facet_count = pow(4, iterations) * 8;
if(m_cVertices != facet_count * 3) {
if(m_sphereVertices) {
free(m_sphereVertices);
m_sphereVertices = NULL;
}
m_cVertices = facet_count * 3;
class Facet3 {
public:
Facet3() {
}
~Facet3() {
}
Vector3 p1;
Vector3 p2;
Vector3 p3;
};
std::vector<Facet3> f = std::vector<Facet3>(facet_count);
int i,it;
float a;
Vector3 p[6] = {
Vector3(0,0,1),
Vector3(0,0,-1),
Vector3(-1,-1,0),
Vector3(1,-1,0),
Vector3(1,1,0),
Vector3(-1,1,0)
};
Vector3 pa,pb,pc;
int nt = 0,ntold;
/* Create the level 0 object */
a = 1 / sqrt(2.0);
for (i=0;i<6;i++) {
p[i].x *= a;
p[i].y *= a;
}
f[0].p1 = p[0]; f[0].p2 = p[3]; f[0].p3 = p[4];
f[1].p1 = p[0]; f[1].p2 = p[4]; f[1].p3 = p[5];
f[2].p1 = p[0]; f[2].p2 = p[5]; f[2].p3 = p[2];
f[3].p1 = p[0]; f[3].p2 = p[2]; f[3].p3 = p[3];
f[4].p1 = p[1]; f[4].p2 = p[4]; f[4].p3 = p[3];
f[5].p1 = p[1]; f[5].p2 = p[5]; f[5].p3 = p[4];
f[6].p1 = p[1]; f[6].p2 = p[2]; f[6].p3 = p[5];
f[7].p1 = p[1]; f[7].p2 = p[3]; f[7].p3 = p[2];
nt = 8;
/* Bisect each edge and move to the surface of a unit sphere */
for (it=0;it<iterations;it++) {
ntold = nt;
for (i=0;i<ntold;i++) {
pa.x = (f[i].p1.x + f[i].p2.x) / 2;
pa.y = (f[i].p1.y + f[i].p2.y) / 2;
pa.z = (f[i].p1.z + f[i].p2.z) / 2;
pb.x = (f[i].p2.x + f[i].p3.x) / 2;
pb.y = (f[i].p2.y + f[i].p3.y) / 2;
pb.z = (f[i].p2.z + f[i].p3.z) / 2;
pc.x = (f[i].p3.x + f[i].p1.x) / 2;
pc.y = (f[i].p3.y + f[i].p1.y) / 2;
pc.z = (f[i].p3.z + f[i].p1.z) / 2;
pa.normalize();
pb.normalize();
pc.normalize();
f[nt].p1 = f[i].p1; f[nt].p2 = pa; f[nt].p3 = pc; nt++;
f[nt].p1 = pa; f[nt].p2 = f[i].p2; f[nt].p3 = pb; nt++;
f[nt].p1 = pb; f[nt].p2 = f[i].p3; f[nt].p3 = pc; nt++;
f[i].p1 = pa;
f[i].p2 = pb;
f[i].p3 = pc;
}
}
m_sphereVertices = (GLfloat *)malloc(sizeof(GLfloat) * m_cVertices * 3);
assert(m_sphereVertices != NULL);
GLfloat *pDest = m_sphereVertices;
for(int facet_index=0; facet_index < facet_count; facet_index++) {
*pDest++ = f[facet_index].p1.x;
*pDest++ = f[facet_index].p1.y;
*pDest++ = f[facet_index].p1.z;
*pDest++ = f[facet_index].p2.x;
*pDest++ = f[facet_index].p2.y;
*pDest++ = f[facet_index].p2.z;
*pDest++ = f[facet_index].p3.x;
*pDest++ = f[facet_index].p3.y;
*pDest++ = f[facet_index].p3.z;
}
}
}
//
// KRPointLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRPointLight.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRStockGeometry.h"
KRPointLight::KRPointLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
m_sphereVertices = NULL;
m_cVertices = 0;
}
KRPointLight::~KRPointLight()
{
if(m_sphereVertices) {
delete m_sphereVertices;
m_cVertices = 0;
}
}
std::string KRPointLight::getElementName() {
return "point_light";
}
AABB KRPointLight::getBounds() {
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
if(influence_radius < m_flareOcclusionSize) {
influence_radius = m_flareOcclusionSize;
}
return AABB::Create(Vector3::Create(-influence_radius), Vector3::Create(influence_radius), getModelMatrix());
}
void KRPointLight::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRLight::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && pCamera->settings.bShowDeferred;
if(renderPass == KRNode::RENDER_PASS_DEFERRED_LIGHTS || bVisualize) {
// Lights are rendered on the second pass of the deferred renderer
std::vector<KRPointLight *> this_light;
this_light.push_back(this);
Vector3 light_position = getLocalTranslation();
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
Matrix4 sphereModelMatrix = Matrix4();
sphereModelMatrix.scale(influence_radius);
sphereModelMatrix.translate(light_position.x, light_position.y, light_position.z);
if(viewport.visible(getBounds())) { // Cull out any lights not within the view frustrum
Vector3 view_light_position = Matrix4::Dot(viewport.getViewMatrix(), light_position);
bool bInsideLight = view_light_position.sqrMagnitude() <= (influence_radius + pCamera->settings.getPerspectiveNearZ()) * (influence_radius + pCamera->settings.getPerspectiveNearZ());
KRShader *pShader = getContext().getShaderManager()->getShader(bVisualize ? "visualize_overlay" : (bInsideLight ? "light_point_inside" : "light_point"), pCamera, this_light, std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 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, sphereModelMatrix, this_light, std::vector<KRDirectionalLight *>(), std::vector<KRSpotLight *>(), 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_COLOR, m_color);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_INTENSITY, m_intensity * 0.01f);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_DECAY_START, getDecayStart());
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_CUTOFF, KRLIGHT_MIN_INFLUENCE);
pShader->setUniform(KRShader::KRENGINE_UNIFORM_LIGHT_POSITION, light_position);
if(bVisualize) {
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
}
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
if(bInsideLight) {
// Disable z-buffer test
GLDEBUG(glDisable(GL_DEPTH_TEST));
// Render a full screen quad
m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
} else {
#if GL_OES_vertex_array_object
GLDEBUG(glBindVertexArrayOES(0));
#endif
m_pContext->getMeshManager()->configureAttribs(1 << KRMesh::KRENGINE_ATTRIB_VERTEX);
// Render sphere of light's influence
generateMesh();
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
GLDEBUG(glVertexAttribPointer(KRMesh::KRENGINE_ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, m_sphereVertices));
GLDEBUG(glDrawArrays(GL_TRIANGLES, 0, m_cVertices));
}
}
if(bVisualize) {
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
}
void KRPointLight::generateMesh() {
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3;
int facet_count = pow(4, iterations) * 8;
if(m_cVertices != facet_count * 3) {
if(m_sphereVertices) {
free(m_sphereVertices);
m_sphereVertices = NULL;
}
m_cVertices = facet_count * 3;
class Facet3 {
public:
Facet3() {
}
~Facet3() {
}
Vector3 p1;
Vector3 p2;
Vector3 p3;
};
std::vector<Facet3> f = std::vector<Facet3>(facet_count);
int i,it;
float a;
Vector3 p[6] = {
Vector3::Create(0,0,1),
Vector3::Create(0,0,-1),
Vector3::Create(-1,-1,0),
Vector3::Create(1,-1,0),
Vector3::Create(1,1,0),
Vector3::Create(-1,1,0)
};
Vector3 pa,pb,pc;
int nt = 0,ntold;
/* Create the level 0 object */
a = 1.0f / sqrtf(2.0f);
for (i=0;i<6;i++) {
p[i].x *= a;
p[i].y *= a;
}
f[0].p1 = p[0]; f[0].p2 = p[3]; f[0].p3 = p[4];
f[1].p1 = p[0]; f[1].p2 = p[4]; f[1].p3 = p[5];
f[2].p1 = p[0]; f[2].p2 = p[5]; f[2].p3 = p[2];
f[3].p1 = p[0]; f[3].p2 = p[2]; f[3].p3 = p[3];
f[4].p1 = p[1]; f[4].p2 = p[4]; f[4].p3 = p[3];
f[5].p1 = p[1]; f[5].p2 = p[5]; f[5].p3 = p[4];
f[6].p1 = p[1]; f[6].p2 = p[2]; f[6].p3 = p[5];
f[7].p1 = p[1]; f[7].p2 = p[3]; f[7].p3 = p[2];
nt = 8;
/* Bisect each edge and move to the surface of a unit sphere */
for (it=0;it<iterations;it++) {
ntold = nt;
for (i=0;i<ntold;i++) {
pa.x = (f[i].p1.x + f[i].p2.x) / 2;
pa.y = (f[i].p1.y + f[i].p2.y) / 2;
pa.z = (f[i].p1.z + f[i].p2.z) / 2;
pb.x = (f[i].p2.x + f[i].p3.x) / 2;
pb.y = (f[i].p2.y + f[i].p3.y) / 2;
pb.z = (f[i].p2.z + f[i].p3.z) / 2;
pc.x = (f[i].p3.x + f[i].p1.x) / 2;
pc.y = (f[i].p3.y + f[i].p1.y) / 2;
pc.z = (f[i].p3.z + f[i].p1.z) / 2;
pa.normalize();
pb.normalize();
pc.normalize();
f[nt].p1 = f[i].p1; f[nt].p2 = pa; f[nt].p3 = pc; nt++;
f[nt].p1 = pa; f[nt].p2 = f[i].p2; f[nt].p3 = pb; nt++;
f[nt].p1 = pb; f[nt].p2 = f[i].p3; f[nt].p3 = pc; nt++;
f[i].p1 = pa;
f[i].p2 = pb;
f[i].p3 = pc;
}
}
m_sphereVertices = (GLfloat *)malloc(sizeof(GLfloat) * m_cVertices * 3);
assert(m_sphereVertices != NULL);
GLfloat *pDest = m_sphereVertices;
for(int facet_index=0; facet_index < facet_count; facet_index++) {
*pDest++ = f[facet_index].p1.x;
*pDest++ = f[facet_index].p1.y;
*pDest++ = f[facet_index].p1.z;
*pDest++ = f[facet_index].p2.x;
*pDest++ = f[facet_index].p2.y;
*pDest++ = f[facet_index].p2.z;
*pDest++ = f[facet_index].p3.x;
*pDest++ = f[facet_index].p3.y;
*pDest++ = f[facet_index].p3.z;
}
}
}

View File

@@ -1,204 +1,204 @@
//
// KRRenderSettings.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-20.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRRenderSettings.h"
KRRenderSettings::KRRenderSettings()
{
siren_enable = true;
siren_enable_reverb = true;
siren_enable_hrtf = true;
siren_reverb_max_length = 2.0f;
m_enable_realtime_occlusion = false;
bShowShadowBuffer = false;
bShowOctree = false;
bShowDeferred = false;
bEnablePerPixel = true;
bEnableDiffuseMap = true;
bEnableNormalMap = true;
bEnableSpecMap = true;
bEnableReflectionMap = true;
bEnableReflection = true;
bDebugPSSM = false;
bEnableAmbient = true;
bEnableDiffuse = true;
bEnableSpecular = true;
bEnableLightMap = true;
bEnableDeferredLighting = false;
max_anisotropy = 4.0f;
ambient_intensity = Vector3::Zero();
light_intensity = Vector3::One();
perspective_fov = 45.0 * D2R;
perspective_nearz = 0.3f; // was 0.05f
perspective_farz = 1000.0f;
dof_quality = 0;
dof_depth = 0.05f;
dof_falloff = 0.05f;
bEnableFlash = false;
flash_intensity = 1.0f;
flash_depth = 0.7f;
flash_falloff = 0.5f;
bEnableVignette = false;
vignette_radius = 0.4f;
vignette_falloff = 1.0f;
m_cShadowBuffers = 0;
volumetric_environment_enable = false;
volumetric_environment_downsample = 2;
volumetric_environment_max_distance = 100.0f;
volumetric_environment_quality = (50 - 5.0) / 495.0f;
volumetric_environment_intensity = 0.9f;
fog_near = 50.0f;
fog_far = 500.0f;
fog_density = 0.0005f;
fog_color = Vector3(0.45, 0.45, 0.5);
fog_type = 0;
dust_particle_intensity = 0.25f;
dust_particle_enable = false;
m_lodBias = 0.0f;
debug_display = KRENGINE_DEBUG_DISPLAY_NONE;
}
KRRenderSettings::~KRRenderSettings()
{
}
KRRenderSettings& KRRenderSettings::operator=(const KRRenderSettings &s)
{
siren_enable = s.siren_enable;
siren_enable_reverb = s.siren_enable_reverb;
siren_enable_hrtf = s.siren_enable_hrtf;
siren_reverb_max_length = s.siren_reverb_max_length;
bEnablePerPixel = s.bEnablePerPixel;
bEnableDiffuseMap = s.bEnableDiffuseMap;
bEnableNormalMap = s.bEnableNormalMap;
bEnableSpecMap = s.bEnableSpecMap;
bEnableReflectionMap = s.bEnableReflectionMap;
bEnableReflection=s.bEnableReflection;
bEnableLightMap=s.bEnableLightMap;
bDebugPSSM=s.bDebugPSSM;
bShowShadowBuffer=s.bShowShadowBuffer;
bShowOctree=s.bShowOctree;
bShowDeferred=s.bShowDeferred;
bEnableAmbient=s.bEnableAmbient;
bEnableDiffuse=s.bEnableDiffuse;
bEnableSpecular=s.bEnableSpecular;
bEnableDeferredLighting=s.bEnableDeferredLighting;
light_intensity=s.light_intensity;
ambient_intensity=s.ambient_intensity;
perspective_fov=s.perspective_fov;
dof_quality=s.dof_quality;
dof_depth=s.dof_depth;
dof_falloff=s.dof_falloff;
bEnableFlash=s.bEnableFlash;
flash_intensity=s.flash_intensity;
flash_depth=s.flash_depth;
flash_falloff=s.flash_falloff;
bEnableVignette=s.bEnableVignette;
vignette_radius=s.vignette_radius;
vignette_falloff=s.vignette_falloff;
m_viewportSize=s.m_viewportSize;
m_cShadowBuffers=s.m_cShadowBuffers;
m_debug_text=s.m_debug_text;
volumetric_environment_enable=s.volumetric_environment_enable;
volumetric_environment_downsample=s.volumetric_environment_downsample;
volumetric_environment_max_distance=s.volumetric_environment_max_distance;
volumetric_environment_quality=s.volumetric_environment_quality;
volumetric_environment_intensity=s.volumetric_environment_intensity;
fog_near=s.fog_near;
fog_far=s.fog_far;
fog_density=s.fog_density;
fog_color=s.fog_color;
fog_type=s.fog_type;
dust_particle_intensity=s.dust_particle_intensity;
dust_particle_enable=s.dust_particle_enable;
perspective_nearz=s.perspective_nearz;
perspective_farz=s.perspective_farz;
debug_display = s.debug_display;
m_lodBias = s.m_lodBias;
m_enable_realtime_occlusion = s.m_enable_realtime_occlusion;
max_anisotropy = s.max_anisotropy;
return *this;
}
const Vector2 &KRRenderSettings::getViewportSize() {
return m_viewportSize;
}
void KRRenderSettings::setViewportSize(const Vector2 &size) {
m_viewportSize = size;
}
float KRRenderSettings::getPerspectiveNearZ()
{
return perspective_nearz;
}
float KRRenderSettings::getPerspectiveFarZ()
{
return perspective_farz;
}
void KRRenderSettings::setPerspectiveNear(float v)
{
if(perspective_nearz != v) {
perspective_nearz = v;
}
}
void KRRenderSettings::setPerpsectiveFarZ(float v)
{
if(perspective_farz != v) {
perspective_farz = v;
}
}
float KRRenderSettings::getLODBias()
{
return m_lodBias;
}
void KRRenderSettings::setLODBias(float v)
{
m_lodBias = v;
}
bool KRRenderSettings::getEnableRealtimeOcclusion()
{
return m_enable_realtime_occlusion;
}
void KRRenderSettings::setEnableRealtimeOcclusion(bool enable)
{
m_enable_realtime_occlusion = enable;
//
// KRRenderSettings.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-20.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRRenderSettings.h"
KRRenderSettings::KRRenderSettings()
{
siren_enable = true;
siren_enable_reverb = true;
siren_enable_hrtf = true;
siren_reverb_max_length = 2.0f;
m_enable_realtime_occlusion = false;
bShowShadowBuffer = false;
bShowOctree = false;
bShowDeferred = false;
bEnablePerPixel = true;
bEnableDiffuseMap = true;
bEnableNormalMap = true;
bEnableSpecMap = true;
bEnableReflectionMap = true;
bEnableReflection = true;
bDebugPSSM = false;
bEnableAmbient = true;
bEnableDiffuse = true;
bEnableSpecular = true;
bEnableLightMap = true;
bEnableDeferredLighting = false;
max_anisotropy = 4.0f;
ambient_intensity = Vector3::Zero();
light_intensity = Vector3::One();
perspective_fov = 45.0f * D2R;
perspective_nearz = 0.3f; // was 0.05f
perspective_farz = 1000.0f;
dof_quality = 0;
dof_depth = 0.05f;
dof_falloff = 0.05f;
bEnableFlash = false;
flash_intensity = 1.0f;
flash_depth = 0.7f;
flash_falloff = 0.5f;
bEnableVignette = false;
vignette_radius = 0.4f;
vignette_falloff = 1.0f;
m_cShadowBuffers = 0;
volumetric_environment_enable = false;
volumetric_environment_downsample = 2;
volumetric_environment_max_distance = 100.0f;
volumetric_environment_quality = (50.0f - 5.0f) / 495.0f;
volumetric_environment_intensity = 0.9f;
fog_near = 50.0f;
fog_far = 500.0f;
fog_density = 0.0005f;
fog_color = Vector3::Create(0.45f, 0.45f, 0.5f);
fog_type = 0;
dust_particle_intensity = 0.25f;
dust_particle_enable = false;
m_lodBias = 0.0f;
debug_display = KRENGINE_DEBUG_DISPLAY_NONE;
}
KRRenderSettings::~KRRenderSettings()
{
}
KRRenderSettings& KRRenderSettings::operator=(const KRRenderSettings &s)
{
siren_enable = s.siren_enable;
siren_enable_reverb = s.siren_enable_reverb;
siren_enable_hrtf = s.siren_enable_hrtf;
siren_reverb_max_length = s.siren_reverb_max_length;
bEnablePerPixel = s.bEnablePerPixel;
bEnableDiffuseMap = s.bEnableDiffuseMap;
bEnableNormalMap = s.bEnableNormalMap;
bEnableSpecMap = s.bEnableSpecMap;
bEnableReflectionMap = s.bEnableReflectionMap;
bEnableReflection=s.bEnableReflection;
bEnableLightMap=s.bEnableLightMap;
bDebugPSSM=s.bDebugPSSM;
bShowShadowBuffer=s.bShowShadowBuffer;
bShowOctree=s.bShowOctree;
bShowDeferred=s.bShowDeferred;
bEnableAmbient=s.bEnableAmbient;
bEnableDiffuse=s.bEnableDiffuse;
bEnableSpecular=s.bEnableSpecular;
bEnableDeferredLighting=s.bEnableDeferredLighting;
light_intensity=s.light_intensity;
ambient_intensity=s.ambient_intensity;
perspective_fov=s.perspective_fov;
dof_quality=s.dof_quality;
dof_depth=s.dof_depth;
dof_falloff=s.dof_falloff;
bEnableFlash=s.bEnableFlash;
flash_intensity=s.flash_intensity;
flash_depth=s.flash_depth;
flash_falloff=s.flash_falloff;
bEnableVignette=s.bEnableVignette;
vignette_radius=s.vignette_radius;
vignette_falloff=s.vignette_falloff;
m_viewportSize=s.m_viewportSize;
m_cShadowBuffers=s.m_cShadowBuffers;
m_debug_text=s.m_debug_text;
volumetric_environment_enable=s.volumetric_environment_enable;
volumetric_environment_downsample=s.volumetric_environment_downsample;
volumetric_environment_max_distance=s.volumetric_environment_max_distance;
volumetric_environment_quality=s.volumetric_environment_quality;
volumetric_environment_intensity=s.volumetric_environment_intensity;
fog_near=s.fog_near;
fog_far=s.fog_far;
fog_density=s.fog_density;
fog_color=s.fog_color;
fog_type=s.fog_type;
dust_particle_intensity=s.dust_particle_intensity;
dust_particle_enable=s.dust_particle_enable;
perspective_nearz=s.perspective_nearz;
perspective_farz=s.perspective_farz;
debug_display = s.debug_display;
m_lodBias = s.m_lodBias;
m_enable_realtime_occlusion = s.m_enable_realtime_occlusion;
max_anisotropy = s.max_anisotropy;
return *this;
}
const Vector2 &KRRenderSettings::getViewportSize() {
return m_viewportSize;
}
void KRRenderSettings::setViewportSize(const Vector2 &size) {
m_viewportSize = size;
}
float KRRenderSettings::getPerspectiveNearZ()
{
return perspective_nearz;
}
float KRRenderSettings::getPerspectiveFarZ()
{
return perspective_farz;
}
void KRRenderSettings::setPerspectiveNear(float v)
{
if(perspective_nearz != v) {
perspective_nearz = v;
}
}
void KRRenderSettings::setPerpsectiveFarZ(float v)
{
if(perspective_farz != v) {
perspective_farz = v;
}
}
float KRRenderSettings::getLODBias()
{
return m_lodBias;
}
void KRRenderSettings::setLODBias(float v)
{
m_lodBias = v;
}
bool KRRenderSettings::getEnableRealtimeOcclusion()
{
return m_enable_realtime_occlusion;
}
void KRRenderSettings::setEnableRealtimeOcclusion(bool enable)
{
m_enable_realtime_occlusion = enable;
}

View File

@@ -1,341 +1,341 @@
//
// KRResource_obj.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-03-22.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRResource.h"
#include "KRMesh.h"
std::vector<KRResource *> KRResource::LoadObj(KRContext &context, const std::string& path)
{
std::vector<KRResource *> resources;
KRMesh *new_mesh = new KRMesh(context, KRResource::GetFileBase(path));
resources.push_back(new_mesh);
KRMesh::mesh_info mi;
std::vector<std::string> material_names_t;
KRDataBlock data;
char szSymbol[500][256];
int *pFaces = NULL;
vector<KRMesh::pack_material *> m_materials;
if(data.load(path)) {
// -----=====----- Get counts -----=====-----
int cVertexData = 0;
int cFaces = 1;
int cMaterialFaceStart = 1;
char *pScan = (char *)data.getStart();
char *pEnd = (char *)data.getEnd();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
*pDest++ = *pScan++;
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(strcmp(szSymbol[0], "v") == 0) {
// Vertex (v)
} else if(strcmp(szSymbol[0], "vt") == 0) {
// Vertex Texture UV Coordinate (vt)
} else if(strcmp(szSymbol[0], "vn") == 0) {
// Vertex Normal (vn)
} else if(strcmp(szSymbol[0], "f") == 0) {
// Face (f)
int cFaceVertexes = (cSymbols - 3) * 3; // 3 vertexes per triangle. Triangles have 4 symbols. Quads have 5 symbols and generate two triangles.
cVertexData += cFaceVertexes;
cFaces += cFaceVertexes * 3 + 1; // Allocate space for count of vertices, Vertex Index, Texture Coordinate Index, and Normal Index
} else if(strcmp(szSymbol[0], "usemtl") == 0) {
// Use Material (usemtl)
if(cMaterialFaceStart - cFaces > 0) {
cFaces++;
}
material_names_t.push_back(std::string(szSymbol[1]));
}
}
}
// -----=====----- Populate vertexes and faces -----=====-----
int *pFaces = (int *)malloc(sizeof(int) * (cFaces + 1));
assert(pFaces != NULL);
std::vector<Vector3> indexed_vertices;
std::vector<Vector2> indexed_uva;
std::vector<Vector3> indexed_normals;
int *pFace = pFaces;
int *pMaterialFaces = pFace++;
*pMaterialFaces = 0;
// --------
pScan = (char *)data.getStart();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
*pDest++ = *pScan++;
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(strcmp(szSymbol[0], "v") == 0) {
// Vertex (v)
float x, y, z;
char *pChar = szSymbol[1];
x = strtof(pChar, &pChar);
pChar = szSymbol[2];
y = strtof(pChar, &pChar);
pChar = szSymbol[3];
z = strtof(pChar, &pChar);
indexed_vertices.push_back(Vector3(x,y,z));
} else if(strcmp(szSymbol[0], "vt") == 0) {
// Vertex Texture UV Coordinate (vt)
char *pChar = szSymbol[1];
float u,v;
u = strtof(pChar, &pChar);
pChar = szSymbol[2];
v = strtof(pChar, &pChar);
indexed_uva.push_back(Vector2(u,v));
} else if(strcmp(szSymbol[0], "vn") == 0) {
// Vertex Normal (vn)
float x,y,z;
char *pChar = szSymbol[1];
x = strtof(pChar, &pChar);
pChar = szSymbol[2];
y = strtof(pChar, &pChar);
pChar = szSymbol[3];
z = strtof(pChar, &pChar);
indexed_normals.push_back(Vector3(x,y,z));
} else if(strcmp(szSymbol[0], "f") == 0) {
// Face (f)
int cFaceVertices = cSymbols - 1;
*pFace++ = cFaceVertices;
for(int iSymbol=1; iSymbol < cSymbols; iSymbol++) {
char *pChar = szSymbol[iSymbol];
if(*pChar == '.' || (*pChar >= '0' && *pChar <= '9')) {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Vertex Index
if(*pChar == '/') {
pChar++;
if(*pChar == '/') {
*pFace++ = -1;
} else {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Texture Coordinate Index
}
} else {
*pFace++ = -1;
}
if(*pChar == '/') {
pChar++;
if(*pChar == '/') {
*pFace++ = -1;
} else {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Normal Index
}
} else {
*pFace++ = -1;
}
while(*pChar == '/') {
pChar++;
strtol(pChar, &pChar, 10);
}
}
}
} else if(strcmp(szSymbol[0], "usemtl") == 0) {
// Use Material (usemtl)
if(pFace - pMaterialFaces > 1) {
*pMaterialFaces = pFace - pMaterialFaces - 1;
pMaterialFaces = pFace++;
}
}
}
}
*pMaterialFaces = pFace - pMaterialFaces - 1;
*pFace++ = 0;
int iVertex = 0;
std::vector<std::string>::iterator material_itr = material_names_t.begin();
KRMesh::pack_material *pMaterial = new KRMesh::pack_material();
pMaterial->start_vertex = iVertex;
pMaterial->vertex_count = 0;
memset(pMaterial->szName, 256, 0);
if(material_itr < material_names_t.end()) {
strncpy(pMaterial->szName, (*material_itr++).c_str(), 256);
}
m_materials.push_back(pMaterial);
pFace = pFaces;
while(*pFace != 0 && iVertex < cVertexData) {
pMaterial->start_vertex = iVertex;
int *pMaterialEndFace = pFace + *pFace;
++pFace;
while(pFace < pMaterialEndFace && iVertex < cVertexData) {
int cFaceVertexes = *pFace;
Vector3 firstFaceVertex;
Vector3 prevFaceVertex;
Vector3 firstFaceNormal;
Vector3 prevFaceNormal;
Vector2 firstFaceUva;
Vector2 prevFaceUva;
for(int iFaceVertex=0; iFaceVertex < cFaceVertexes; iFaceVertex++) {
if(iFaceVertex > 2) {
// There have already been 3 vertices. Now we need to split the quad into a second triangle composed of the 1st, 3rd, and 4th vertices
iVertex+=2;
mi.vertices.push_back(firstFaceVertex);
mi.uva.push_back(firstFaceUva);
mi.normals.push_back(firstFaceNormal);
mi.vertices.push_back(prevFaceVertex);
mi.uva.push_back(prevFaceUva);
mi.normals.push_back(prevFaceNormal);
}
Vector3 vertex = indexed_vertices[pFace[iFaceVertex*3+1]];
Vector2 new_uva;
if(pFace[iFaceVertex*3+2] >= 0) {
new_uva = indexed_uva[pFace[iFaceVertex*3+2]];
}
Vector3 normal;
if(pFace[iFaceVertex*3+3] >= 0){
Vector3 normal = indexed_normals[pFace[iFaceVertex*3+3]];
}
mi.vertices.push_back(vertex);
mi.uva.push_back(new_uva);
mi.normals.push_back(normal);
if(iFaceVertex==0) {
firstFaceVertex = vertex;
firstFaceUva = new_uva;
firstFaceNormal = normal;
}
prevFaceVertex = vertex;
prevFaceUva = new_uva;
prevFaceNormal = normal;
iVertex++;
}
pFace += cFaceVertexes * 3 + 1;
}
pMaterial->vertex_count = iVertex - pMaterial->start_vertex;
if(*pFace != 0) {
pMaterial = new KRMesh::pack_material();
pMaterial->start_vertex = iVertex;
pMaterial->vertex_count = 0;
memset(pMaterial->szName, 256, 0);
if(material_itr < material_names_t.end()) {
strncpy(pMaterial->szName, (*material_itr++).c_str(), 256);
}
m_materials.push_back(pMaterial);
}
}
for(int iMaterial=0; iMaterial < m_materials.size(); iMaterial++) {
KRMesh::pack_material *pNewMaterial = m_materials[iMaterial];
if(pNewMaterial->vertex_count > 0) {
mi.material_names.push_back(std::string(pNewMaterial->szName));
mi.submesh_starts.push_back(pNewMaterial->start_vertex);
mi.submesh_lengths.push_back(pNewMaterial->vertex_count);
}
delete pNewMaterial;
}
// TODO: Bones not yet supported for OBJ
// std::vector<std::string> bone_names;
// std::vector<Matrix4> bone_bind_poses;
// std::vector<std::vector<int> > bone_indexes;
// std::vector<std::vector<float> > bone_weights;
//
// std::vector<__uint16_t> vertex_indexes;
// std::vector<std::pair<int, int> > vertex_index_bases;
mi.format = KRMesh::KRENGINE_MODEL_FORMAT_TRIANGLES;
new_mesh->LoadData(mi, true, false);
}
if(pFaces) {
free(pFaces);
}
return resources;
}
//
// KRResource_obj.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-03-22.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRResource.h"
#include "KRMesh.h"
std::vector<KRResource *> KRResource::LoadObj(KRContext &context, const std::string& path)
{
std::vector<KRResource *> resources;
KRMesh *new_mesh = new KRMesh(context, KRResource::GetFileBase(path));
resources.push_back(new_mesh);
KRMesh::mesh_info mi;
std::vector<std::string> material_names_t;
KRDataBlock data;
char szSymbol[500][256];
int *pFaces = NULL;
vector<KRMesh::pack_material *> m_materials;
if(data.load(path)) {
// -----=====----- Get counts -----=====-----
int cVertexData = 0;
int cFaces = 1;
int cMaterialFaceStart = 1;
char *pScan = (char *)data.getStart();
char *pEnd = (char *)data.getEnd();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
*pDest++ = *pScan++;
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(strcmp(szSymbol[0], "v") == 0) {
// Vertex (v)
} else if(strcmp(szSymbol[0], "vt") == 0) {
// Vertex Texture UV Coordinate (vt)
} else if(strcmp(szSymbol[0], "vn") == 0) {
// Vertex Normal (vn)
} else if(strcmp(szSymbol[0], "f") == 0) {
// Face (f)
int cFaceVertexes = (cSymbols - 3) * 3; // 3 vertexes per triangle. Triangles have 4 symbols. Quads have 5 symbols and generate two triangles.
cVertexData += cFaceVertexes;
cFaces += cFaceVertexes * 3 + 1; // Allocate space for count of vertices, Vertex Index, Texture Coordinate Index, and Normal Index
} else if(strcmp(szSymbol[0], "usemtl") == 0) {
// Use Material (usemtl)
if(cMaterialFaceStart - cFaces > 0) {
cFaces++;
}
material_names_t.push_back(std::string(szSymbol[1]));
}
}
}
// -----=====----- Populate vertexes and faces -----=====-----
int *pFaces = (int *)malloc(sizeof(int) * (cFaces + 1));
assert(pFaces != NULL);
std::vector<Vector3> indexed_vertices;
std::vector<Vector2> indexed_uva;
std::vector<Vector3> indexed_normals;
int *pFace = pFaces;
int *pMaterialFaces = pFace++;
*pMaterialFaces = 0;
// --------
pScan = (char *)data.getStart();
while(pScan < pEnd) {
// Scan through whitespace
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) {
pScan++;
}
if(*pScan == '#') {
// Line is a comment line
// Scan to the end of the line
while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') {
pScan++;
}
} else {
int cSymbols = 0;
while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') {
char *pDest = szSymbol[cSymbols++];
while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') {
*pDest++ = *pScan++;
}
*pDest = '\0';
// Scan through whitespace, but don't advance to next line
while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) {
pScan++;
}
}
if(strcmp(szSymbol[0], "v") == 0) {
// Vertex (v)
float x, y, z;
char *pChar = szSymbol[1];
x = strtof(pChar, &pChar);
pChar = szSymbol[2];
y = strtof(pChar, &pChar);
pChar = szSymbol[3];
z = strtof(pChar, &pChar);
indexed_vertices.push_back(Vector3::Create(x,y,z));
} else if(strcmp(szSymbol[0], "vt") == 0) {
// Vertex Texture UV Coordinate (vt)
char *pChar = szSymbol[1];
float u,v;
u = strtof(pChar, &pChar);
pChar = szSymbol[2];
v = strtof(pChar, &pChar);
indexed_uva.push_back(Vector2::Create(u,v));
} else if(strcmp(szSymbol[0], "vn") == 0) {
// Vertex Normal (vn)
float x,y,z;
char *pChar = szSymbol[1];
x = strtof(pChar, &pChar);
pChar = szSymbol[2];
y = strtof(pChar, &pChar);
pChar = szSymbol[3];
z = strtof(pChar, &pChar);
indexed_normals.push_back(Vector3::Create(x,y,z));
} else if(strcmp(szSymbol[0], "f") == 0) {
// Face (f)
int cFaceVertices = cSymbols - 1;
*pFace++ = cFaceVertices;
for(int iSymbol=1; iSymbol < cSymbols; iSymbol++) {
char *pChar = szSymbol[iSymbol];
if(*pChar == '.' || (*pChar >= '0' && *pChar <= '9')) {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Vertex Index
if(*pChar == '/') {
pChar++;
if(*pChar == '/') {
*pFace++ = -1;
} else {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Texture Coordinate Index
}
} else {
*pFace++ = -1;
}
if(*pChar == '/') {
pChar++;
if(*pChar == '/') {
*pFace++ = -1;
} else {
*pFace++ = strtol(pChar, &pChar, 10) - 1; // Normal Index
}
} else {
*pFace++ = -1;
}
while(*pChar == '/') {
pChar++;
strtol(pChar, &pChar, 10);
}
}
}
} else if(strcmp(szSymbol[0], "usemtl") == 0) {
// Use Material (usemtl)
if(pFace - pMaterialFaces > 1) {
*pMaterialFaces = pFace - pMaterialFaces - 1;
pMaterialFaces = pFace++;
}
}
}
}
*pMaterialFaces = pFace - pMaterialFaces - 1;
*pFace++ = 0;
int iVertex = 0;
std::vector<std::string>::iterator material_itr = material_names_t.begin();
KRMesh::pack_material *pMaterial = new KRMesh::pack_material();
pMaterial->start_vertex = iVertex;
pMaterial->vertex_count = 0;
memset(pMaterial->szName, 256, 0);
if(material_itr < material_names_t.end()) {
strncpy(pMaterial->szName, (*material_itr++).c_str(), 256);
}
m_materials.push_back(pMaterial);
pFace = pFaces;
while(*pFace != 0 && iVertex < cVertexData) {
pMaterial->start_vertex = iVertex;
int *pMaterialEndFace = pFace + *pFace;
++pFace;
while(pFace < pMaterialEndFace && iVertex < cVertexData) {
int cFaceVertexes = *pFace;
Vector3 firstFaceVertex;
Vector3 prevFaceVertex;
Vector3 firstFaceNormal;
Vector3 prevFaceNormal;
Vector2 firstFaceUva;
Vector2 prevFaceUva;
for(int iFaceVertex=0; iFaceVertex < cFaceVertexes; iFaceVertex++) {
if(iFaceVertex > 2) {
// There have already been 3 vertices. Now we need to split the quad into a second triangle composed of the 1st, 3rd, and 4th vertices
iVertex+=2;
mi.vertices.push_back(firstFaceVertex);
mi.uva.push_back(firstFaceUva);
mi.normals.push_back(firstFaceNormal);
mi.vertices.push_back(prevFaceVertex);
mi.uva.push_back(prevFaceUva);
mi.normals.push_back(prevFaceNormal);
}
Vector3 vertex = indexed_vertices[pFace[iFaceVertex*3+1]];
Vector2 new_uva;
if(pFace[iFaceVertex*3+2] >= 0) {
new_uva = indexed_uva[pFace[iFaceVertex*3+2]];
}
Vector3 normal;
if(pFace[iFaceVertex*3+3] >= 0){
Vector3 normal = indexed_normals[pFace[iFaceVertex*3+3]];
}
mi.vertices.push_back(vertex);
mi.uva.push_back(new_uva);
mi.normals.push_back(normal);
if(iFaceVertex==0) {
firstFaceVertex = vertex;
firstFaceUva = new_uva;
firstFaceNormal = normal;
}
prevFaceVertex = vertex;
prevFaceUva = new_uva;
prevFaceNormal = normal;
iVertex++;
}
pFace += cFaceVertexes * 3 + 1;
}
pMaterial->vertex_count = iVertex - pMaterial->start_vertex;
if(*pFace != 0) {
pMaterial = new KRMesh::pack_material();
pMaterial->start_vertex = iVertex;
pMaterial->vertex_count = 0;
memset(pMaterial->szName, 256, 0);
if(material_itr < material_names_t.end()) {
strncpy(pMaterial->szName, (*material_itr++).c_str(), 256);
}
m_materials.push_back(pMaterial);
}
}
for(int iMaterial=0; iMaterial < m_materials.size(); iMaterial++) {
KRMesh::pack_material *pNewMaterial = m_materials[iMaterial];
if(pNewMaterial->vertex_count > 0) {
mi.material_names.push_back(std::string(pNewMaterial->szName));
mi.submesh_starts.push_back(pNewMaterial->start_vertex);
mi.submesh_lengths.push_back(pNewMaterial->vertex_count);
}
delete pNewMaterial;
}
// TODO: Bones not yet supported for OBJ
// std::vector<std::string> bone_names;
// std::vector<Matrix4> bone_bind_poses;
// std::vector<std::vector<int> > bone_indexes;
// std::vector<std::vector<float> > bone_weights;
//
// std::vector<__uint16_t> vertex_indexes;
// std::vector<std::pair<int, int> > vertex_index_bases;
mi.format = KRMesh::KRENGINE_MODEL_FORMAT_TRIANGLES;
new_mesh->LoadData(mi, true, false);
}
if(pFaces) {
free(pFaces);
}
return resources;
}

View File

@@ -1,166 +1,166 @@
//
// KRReverbZone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRReverbZone.h"
#include "KRContext.h"
KRReverbZone::KRReverbZone(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_reverb = "";
m_reverb_gain = 1.0f;
m_gradient_distance = 0.25f;
}
KRReverbZone::~KRReverbZone()
{
}
std::string KRReverbZone::getElementName() {
return "reverb_zone";
}
tinyxml2::XMLElement *KRReverbZone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("zone", m_zone.c_str());
e->SetAttribute("sample", m_reverb.c_str());
e->SetAttribute("gain", m_reverb_gain);
e->SetAttribute("gradient", m_gradient_distance);
return e;
}
void KRReverbZone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_zone = e->Attribute("zone");
m_gradient_distance = 0.25f;
if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) {
m_gradient_distance = 0.25f;
}
m_reverb = e->Attribute("sample");
m_reverb_gain = 1.0f;
if(e->QueryFloatAttribute("gain", &m_reverb_gain) != tinyxml2::XML_SUCCESS) {
m_reverb_gain = 1.0f;
}
}
std::string KRReverbZone::getReverb()
{
return m_reverb;
}
void KRReverbZone::setReverb(const std::string &reverb)
{
m_reverb = reverb;
}
float KRReverbZone::getReverbGain()
{
return m_reverb_gain;
}
void KRReverbZone::setReverbGain(float reverb_gain)
{
m_reverb_gain = reverb_gain;
}
std::string KRReverbZone::getZone()
{
return m_zone;
}
void KRReverbZone::setZone(const std::string &zone)
{
m_zone = zone;
}
void KRReverbZone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_SIREN_REVERB_ZONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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));
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
float KRReverbZone::getGradientDistance()
{
return m_gradient_distance;
}
void KRReverbZone::setGradientDistance(float gradient_distance)
{
m_gradient_distance = gradient_distance;
}
AABB KRReverbZone::getBounds() {
// Reverb zones always have a -1, -1, -1 to 1, 1, 1 bounding box
return AABB(-Vector3::One(), Vector3::One(), getModelMatrix());
}
float KRReverbZone::getContainment(const Vector3 &pos)
{
AABB bounds = getBounds();
if(bounds.contains(pos)) {
Vector3 size = bounds.size();
Vector3 diff = pos - bounds.center();
diff = diff * 2.0f;
diff = Vector3(diff.x / size.x, diff.y / size.y, diff.z / size.z);
float d = diff.magnitude();
if(m_gradient_distance <= 0.0f) {
// Avoid division by zero
d = d > 1.0f ? 0.0f : 1.0f;
} else {
d = (1.0f - d) / m_gradient_distance;
d = KRCLAMP(d, 0.0f, 1.0f);
}
return d;
} else {
return 0.0f;
}
//
// KRReverbZone.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-12-06.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRReverbZone.h"
#include "KRContext.h"
KRReverbZone::KRReverbZone(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_reverb = "";
m_reverb_gain = 1.0f;
m_gradient_distance = 0.25f;
}
KRReverbZone::~KRReverbZone()
{
}
std::string KRReverbZone::getElementName() {
return "reverb_zone";
}
tinyxml2::XMLElement *KRReverbZone::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("zone", m_zone.c_str());
e->SetAttribute("sample", m_reverb.c_str());
e->SetAttribute("gain", m_reverb_gain);
e->SetAttribute("gradient", m_gradient_distance);
return e;
}
void KRReverbZone::loadXML(tinyxml2::XMLElement *e)
{
KRNode::loadXML(e);
m_zone = e->Attribute("zone");
m_gradient_distance = 0.25f;
if(e->QueryFloatAttribute("gradient", &m_gradient_distance) != tinyxml2::XML_SUCCESS) {
m_gradient_distance = 0.25f;
}
m_reverb = e->Attribute("sample");
m_reverb_gain = 1.0f;
if(e->QueryFloatAttribute("gain", &m_reverb_gain) != tinyxml2::XML_SUCCESS) {
m_reverb_gain = 1.0f;
}
}
std::string KRReverbZone::getReverb()
{
return m_reverb;
}
void KRReverbZone::setReverb(const std::string &reverb)
{
m_reverb = reverb;
}
float KRReverbZone::getReverbGain()
{
return m_reverb_gain;
}
void KRReverbZone::setReverbGain(float reverb_gain)
{
m_reverb_gain = reverb_gain;
}
std::string KRReverbZone::getZone()
{
return m_zone;
}
void KRReverbZone::setZone(const std::string &zone)
{
m_zone = zone;
}
void KRReverbZone::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass)
{
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
bool bVisualize = pCamera->settings.debug_display == KRRenderSettings::KRENGINE_DEBUG_DISPLAY_SIREN_REVERB_ZONES;
if(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT && bVisualize) {
Matrix4 sphereModelMatrix = getModelMatrix();
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, sphereModelMatrix, point_lights, directional_lights, spot_lights, 0, renderPass, Vector3::Zero(), 0.0f, Vector4::Zero())) {
// 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));
std::vector<KRMesh *> sphereModels = getContext().getMeshManager()->getModel("__sphere");
if(sphereModels.size()) {
for(int i=0; i < sphereModels[0]->getSubmeshCount(); i++) {
sphereModels[0]->renderSubmesh(i, renderPass, getName(), "visualize_overlay", 1.0f);
}
}
// Enable alpha blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
}
}
float KRReverbZone::getGradientDistance()
{
return m_gradient_distance;
}
void KRReverbZone::setGradientDistance(float gradient_distance)
{
m_gradient_distance = gradient_distance;
}
AABB KRReverbZone::getBounds() {
// Reverb zones always have a -1, -1, -1 to 1, 1, 1 bounding box
return AABB::Create(-Vector3::One(), Vector3::One(), getModelMatrix());
}
float KRReverbZone::getContainment(const Vector3 &pos)
{
AABB bounds = getBounds();
if(bounds.contains(pos)) {
Vector3 size = bounds.size();
Vector3 diff = pos - bounds.center();
diff = diff * 2.0f;
diff = Vector3::Create(diff.x / size.x, diff.y / size.y, diff.z / size.z);
float d = diff.magnitude();
if(m_gradient_distance <= 0.0f) {
// Avoid division by zero
d = d > 1.0f ? 0.0f : 1.0f;
} else {
d = (1.0f - d) / m_gradient_distance;
d = KRCLAMP(d, 0.0f, 1.0f);
}
return d;
} else {
return 0.0f;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +1,61 @@
//
// KRSpotLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRSpotLight.h"
KRSpotLight::KRSpotLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
}
KRSpotLight::~KRSpotLight()
{
}
std::string KRSpotLight::getElementName() {
return "spot_light";
}
tinyxml2::XMLElement *KRSpotLight::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRLight::saveXML(parent);
e->SetAttribute("inner_angle", m_innerAngle);
e->SetAttribute("outer_angle", m_outerAngle);
return e;
}
void KRSpotLight::loadXML(tinyxml2::XMLElement *e) {
KRLight::loadXML(e);
e->QueryFloatAttribute("inner_angle", &m_innerAngle);
e->QueryFloatAttribute("outer_angle", &m_outerAngle);
}
float KRSpotLight::getInnerAngle() {
return m_innerAngle;
}
float KRSpotLight::getOuterAngle() {
return m_outerAngle;
}
void KRSpotLight::setInnerAngle(float innerAngle) {
m_innerAngle = innerAngle;
}
void KRSpotLight::setOuterAngle(float outerAngle) {
m_outerAngle = outerAngle;
}
AABB KRSpotLight::getBounds() {
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
if(influence_radius < m_flareOcclusionSize) {
influence_radius = m_flareOcclusionSize;
}
return AABB(Vector3(-influence_radius), Vector3(influence_radius), getModelMatrix());
}
//
// KRSpotLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRSpotLight.h"
KRSpotLight::KRSpotLight(KRScene &scene, std::string name) : KRLight(scene, name)
{
}
KRSpotLight::~KRSpotLight()
{
}
std::string KRSpotLight::getElementName() {
return "spot_light";
}
tinyxml2::XMLElement *KRSpotLight::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRLight::saveXML(parent);
e->SetAttribute("inner_angle", m_innerAngle);
e->SetAttribute("outer_angle", m_outerAngle);
return e;
}
void KRSpotLight::loadXML(tinyxml2::XMLElement *e) {
KRLight::loadXML(e);
e->QueryFloatAttribute("inner_angle", &m_innerAngle);
e->QueryFloatAttribute("outer_angle", &m_outerAngle);
}
float KRSpotLight::getInnerAngle() {
return m_innerAngle;
}
float KRSpotLight::getOuterAngle() {
return m_outerAngle;
}
void KRSpotLight::setInnerAngle(float innerAngle) {
m_innerAngle = innerAngle;
}
void KRSpotLight::setOuterAngle(float outerAngle) {
m_outerAngle = outerAngle;
}
AABB KRSpotLight::getBounds() {
float influence_radius = m_decayStart - sqrt(m_intensity * 0.01f) / sqrt(KRLIGHT_MIN_INFLUENCE);
if(influence_radius < m_flareOcclusionSize) {
influence_radius = m_flareOcclusionSize;
}
return AABB::Create(Vector3::Create(-influence_radius), Vector3::Create(influence_radius), getModelMatrix());
}

View File

@@ -1,141 +1,141 @@
//
// KRSprite.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRSprite.h"
#include "KRNode.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRShaderManager.h"
#include "KRShader.h"
#include "KRStockGeometry.h"
#include "KRDirectionalLight.h"
#include "KRSpotLight.h"
#include "KRPointLight.h"
KRSprite::KRSprite(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_spriteTexture = "";
m_pSpriteTexture = NULL;
m_spriteAlpha = 1.0f;
}
KRSprite::~KRSprite()
{
}
std::string KRSprite::getElementName() {
return "sprite";
}
tinyxml2::XMLElement *KRSprite::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("sprite_texture", m_spriteTexture.c_str());
e->SetAttribute("sprite_alpha", m_spriteAlpha);
return e;
}
void KRSprite::loadXML(tinyxml2::XMLElement *e) {
KRNode::loadXML(e);
if(e->QueryFloatAttribute("sprite_alpha", &m_spriteAlpha) != tinyxml2::XML_SUCCESS) {
m_spriteAlpha = 1.0f;
}
const char *szSpriteTexture = e->Attribute("sprite_texture");
if(szSpriteTexture) {
m_spriteTexture = szSpriteTexture;
} else {
m_spriteTexture = "";
}
m_pSpriteTexture = NULL;
}
void KRSprite::setSpriteTexture(std::string sprite_texture) {
m_spriteTexture = sprite_texture;
m_pSpriteTexture = NULL;
}
void KRSprite::setSpriteAlpha(float alpha)
{
m_spriteAlpha = alpha;
}
float KRSprite::getSpriteAlpha() const
{
return m_spriteAlpha;
}
AABB KRSprite::getBounds() {
return AABB(-Vector3::One() * 0.5f, Vector3::One() * 0.5f, getModelMatrix());
}
void KRSprite::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible >= LOD_VISIBILITY_PRESTREAM && renderPass == KRNode::RENDER_PASS_PRESTREAM) {
// Pre-stream sprites, even if the alpha is zero
if(m_spriteTexture.size() && m_pSpriteTexture == NULL) {
if(!m_pSpriteTexture && m_spriteTexture.size()) {
m_pSpriteTexture = getContext().getTextureManager()->getTexture(m_spriteTexture);
}
}
if(m_pSpriteTexture) {
m_pSpriteTexture->resetPoolExpiry(0.0f, KRTexture::TEXTURE_USAGE_SPRITE);
}
}
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES) {
if(m_spriteTexture.size() && m_spriteAlpha > 0.0f) {
if(!m_pSpriteTexture && m_spriteTexture.size()) {
m_pSpriteTexture = getContext().getTextureManager()->getTexture(m_spriteTexture);
}
if(m_pSpriteTexture) {
/*
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
*/
// TODO - Sprites are currently additive only. Need to expose this and allow for multiple blending modes
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Render light sprite on transparency pass
KRShader *pShader = getContext().getShaderManager()->getShader("sprite", 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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_spriteAlpha);
m_pContext->getTextureManager()->selectTexture(0, m_pSpriteTexture, 0.0f, KRTexture::TEXTURE_USAGE_SPRITE);
m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
}
}
//
// KRSprite.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KREngine-common.h"
#include "KRSprite.h"
#include "KRNode.h"
#include "KRCamera.h"
#include "KRContext.h"
#include "KRShaderManager.h"
#include "KRShader.h"
#include "KRStockGeometry.h"
#include "KRDirectionalLight.h"
#include "KRSpotLight.h"
#include "KRPointLight.h"
KRSprite::KRSprite(KRScene &scene, std::string name) : KRNode(scene, name)
{
m_spriteTexture = "";
m_pSpriteTexture = NULL;
m_spriteAlpha = 1.0f;
}
KRSprite::~KRSprite()
{
}
std::string KRSprite::getElementName() {
return "sprite";
}
tinyxml2::XMLElement *KRSprite::saveXML( tinyxml2::XMLNode *parent)
{
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
e->SetAttribute("sprite_texture", m_spriteTexture.c_str());
e->SetAttribute("sprite_alpha", m_spriteAlpha);
return e;
}
void KRSprite::loadXML(tinyxml2::XMLElement *e) {
KRNode::loadXML(e);
if(e->QueryFloatAttribute("sprite_alpha", &m_spriteAlpha) != tinyxml2::XML_SUCCESS) {
m_spriteAlpha = 1.0f;
}
const char *szSpriteTexture = e->Attribute("sprite_texture");
if(szSpriteTexture) {
m_spriteTexture = szSpriteTexture;
} else {
m_spriteTexture = "";
}
m_pSpriteTexture = NULL;
}
void KRSprite::setSpriteTexture(std::string sprite_texture) {
m_spriteTexture = sprite_texture;
m_pSpriteTexture = NULL;
}
void KRSprite::setSpriteAlpha(float alpha)
{
m_spriteAlpha = alpha;
}
float KRSprite::getSpriteAlpha() const
{
return m_spriteAlpha;
}
AABB KRSprite::getBounds() {
return AABB::Create(-Vector3::One() * 0.5f, Vector3::One() * 0.5f, getModelMatrix());
}
void KRSprite::render(KRCamera *pCamera, std::vector<KRPointLight *> &point_lights, std::vector<KRDirectionalLight *> &directional_lights, std::vector<KRSpotLight *>&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass) {
if(m_lod_visible >= LOD_VISIBILITY_PRESTREAM && renderPass == KRNode::RENDER_PASS_PRESTREAM) {
// Pre-stream sprites, even if the alpha is zero
if(m_spriteTexture.size() && m_pSpriteTexture == NULL) {
if(!m_pSpriteTexture && m_spriteTexture.size()) {
m_pSpriteTexture = getContext().getTextureManager()->getTexture(m_spriteTexture);
}
}
if(m_pSpriteTexture) {
m_pSpriteTexture->resetPoolExpiry(0.0f, KRTexture::TEXTURE_USAGE_SPRITE);
}
}
if(m_lod_visible <= LOD_VISIBILITY_PRESTREAM) return;
KRNode::render(pCamera, point_lights, directional_lights, spot_lights, viewport, renderPass);
if(renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES) {
if(m_spriteTexture.size() && m_spriteAlpha > 0.0f) {
if(!m_pSpriteTexture && m_spriteTexture.size()) {
m_pSpriteTexture = getContext().getTextureManager()->getTexture(m_spriteTexture);
}
if(m_pSpriteTexture) {
/*
// Enable additive blending
GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
*/
// TODO - Sprites are currently additive only. Need to expose this and allow for multiple blending modes
// Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST));
GLDEBUG(glDepthFunc(GL_LEQUAL));
GLDEBUG(glDepthRangef(0.0, 1.0));
// Render light sprite on transparency pass
KRShader *pShader = getContext().getShaderManager()->getShader("sprite", 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, Vector3::Zero(), 0.0f, Vector4::Zero())) {
pShader->setUniform(KRShader::KRENGINE_UNIFORM_MATERIAL_ALPHA, m_spriteAlpha);
m_pContext->getTextureManager()->selectTexture(0, m_pSpriteTexture, 0.0f, KRTexture::TEXTURE_USAGE_SPRITE);
m_pContext->getMeshManager()->bindVBO(&m_pContext->getMeshManager()->KRENGINE_VBO_DATA_2D_SQUARE_VERTICES, 1.0f);
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
}
}
}
}
}

View File

@@ -1,385 +1,385 @@
//
// KRTextureTGA.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-23.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRTextureTGA.h"
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRTextureKTX.h"
#if defined(_WIN32) || defined(_WIN64)
#pragma pack(1)
typedef struct {
char idlength;
char colourmaptype;
char imagetype;
short int colourmaporigin;
short int colourmaplength;
char colourmapdepth;
short int x_origin;
short int y_origin;
short width;
short height;
char bitsperpixel;
char imagedescriptor;
} TGA_HEADER;
#pragma pack()
#else
typedef struct {
char idlength;
char colourmaptype;
char imagetype;
short int colourmaporigin;
short int colourmaplength;
char colourmapdepth;
short int x_origin;
short int y_origin;
short width;
short height;
char bitsperpixel;
char imagedescriptor;
} __attribute__((packed)) TGA_HEADER;
#endif
KRTextureTGA::KRTextureTGA(KRContext &context, KRDataBlock *data, std::string name) : KRTexture2D(context, data, name)
{
data->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)data->getStart();
m_max_lod_max_dim = pHeader->width > pHeader->height ? pHeader->width : pHeader->height;
m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images
switch(pHeader->imagetype) {
case 2: // rgb
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 24:
{
m_imageSize = pHeader->width * pHeader->height * 4;
}
break;
case 32:
{
m_imageSize = pHeader->width * pHeader->height * 4;
}
break;
default:
{
assert(false);
}
break;
}
break;
default:
{
assert(false);
break;
}
}
data->unlock();
}
KRTextureTGA::~KRTextureTGA()
{
}
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress, bool premultiply_alpha)
{
m_pData->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart();
unsigned char *pData = (unsigned char *)pHeader + (long)pHeader->idlength + (long)pHeader->colourmaplength * (long)pHeader->colourmaptype + sizeof(TGA_HEADER);
GLenum internal_format = GL_RGBA;
#if !TARGET_OS_IPHONE
if(compress) {
internal_format = pHeader->bitsperpixel == 24 ? GL_COMPRESSED_RGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
#endif
if(pHeader->colourmaptype != 0) {
m_pData->unlock();
return false; // Mapped colors not supported
}
switch(pHeader->imagetype) {
case 2: // rgb
switch(pHeader->bitsperpixel) {
case 24:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
//#ifdef __APPLE__
// vImage_Buffer source_image = { pData, pHeader->height, pHeader->width, pHeader->width*3 };
// vImage_Buffer dest_image = { converted_image, pHeader->height, pHeader->width, pHeader->width*4 };
// vImageConvert_RGB888toRGBA8888(&source_image, NULL, 0xff, &dest_image, false, kvImageDoNotTile);
//#else
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = pData + pHeader->height * pHeader->width * 3;
while(pSource < pEnd) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
pSource += 3;
}
assert(pSource <= m_pData->getEnd());
//#endif
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
case 32:
{
if(premultiply_alpha) {
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = pData + pHeader->height * pHeader->width * 3;
while(pSource < pEnd) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
assert(pSource <= m_pData->getEnd());
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
} else {
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)pData));
GLDEBUG(glFinish());
}
current_lod_max_dim = m_max_lod_max_dim;
}
break;
default:
m_pData->unlock();
return false; // 16-bit images not yet supported
}
break;
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 32:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
if(premultiply_alpha) {
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
} else {
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
pSource += 4;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
}
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
case 24:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
}
pSource += 3;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
pSource += 3;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
default:
m_pData->unlock();
return false; // 16-bit images not yet supported
}
break;
default:
m_pData->unlock();
return false; // Image type not yet supported
}
m_pData->unlock();
return true;
}
#if !TARGET_OS_IPHONE
KRTexture *KRTextureTGA::compress(bool premultiply_alpha)
{
m_pData->lock();
std::list<KRDataBlock *> blocks;
getContext().getTextureManager()->_setActiveTexture(0);
GLuint compressed_handle = 0;
GLDEBUG(glGenTextures(1, &compressed_handle));
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle));
int current_max_dim = 0;
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, true, premultiply_alpha)) {
assert(false); // Failed to upload the texture
}
GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D));
GLint width = 0, height = 0, internal_format, base_internal_format;
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format));
/*
int texture_base_level = 0;
int texture_max_level = 0;
GLDEBUG(glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, &texture_base_level));
GLDEBUG(glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, &texture_max_level));
*/
switch(internal_format)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
base_internal_format = GL_BGRA;
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
base_internal_format = GL_BGRA;
break;
default:
assert(false); // Not yet supported
break;
}
GLuint lod_level = 0;
GLint compressed_size = 0;
int lod_width = width;
while(lod_width > 1) {
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, lod_level, GL_TEXTURE_WIDTH, &lod_width));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, lod_level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressed_size));
KRDataBlock *new_block = new KRDataBlock();
new_block->expand(compressed_size);
new_block->lock();
GLDEBUG(glGetCompressedTexImage(GL_TEXTURE_2D, lod_level, new_block->getStart()));
new_block->unlock();
blocks.push_back(new_block);
lod_level++;
}
assert(lod_width == 1);
GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0));
getContext().getTextureManager()->selectTexture(0, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE);
GLDEBUG(glDeleteTextures(1, &compressed_handle));
KRTextureKTX *new_texture = new KRTextureKTX(getContext(), getName(), internal_format, base_internal_format, width, height, blocks);
m_pData->unlock();
for(auto block_itr = blocks.begin(); block_itr != blocks.end(); block_itr++) {
KRDataBlock *block = *block_itr;
delete block;
}
return new_texture;
}
#endif
long KRTextureTGA::getMemRequiredForSize(int max_dim)
{
return m_imageSize;
}
std::string KRTextureTGA::getExtension()
{
return "tga";
}
//
// KRTextureTGA.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-23.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "KRTextureTGA.h"
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRTextureKTX.h"
#if defined(_WIN32) || defined(_WIN64)
#pragma pack(1)
typedef struct {
char idlength;
char colourmaptype;
char imagetype;
short int colourmaporigin;
short int colourmaplength;
char colourmapdepth;
short int x_origin;
short int y_origin;
short width;
short height;
char bitsperpixel;
char imagedescriptor;
} TGA_HEADER;
#pragma pack()
#else
typedef struct {
char idlength;
char colourmaptype;
char imagetype;
short int colourmaporigin;
short int colourmaplength;
char colourmapdepth;
short int x_origin;
short int y_origin;
short width;
short height;
char bitsperpixel;
char imagedescriptor;
} __attribute__((packed)) TGA_HEADER;
#endif
KRTextureTGA::KRTextureTGA(KRContext &context, KRDataBlock *data, std::string name) : KRTexture2D(context, data, name)
{
data->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)data->getStart();
m_max_lod_max_dim = pHeader->width > pHeader->height ? pHeader->width : pHeader->height;
m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images
switch(pHeader->imagetype) {
case 2: // rgb
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 24:
{
m_imageSize = pHeader->width * pHeader->height * 4;
}
break;
case 32:
{
m_imageSize = pHeader->width * pHeader->height * 4;
}
break;
default:
{
assert(false);
}
break;
}
break;
default:
{
assert(false);
break;
}
}
data->unlock();
}
KRTextureTGA::~KRTextureTGA()
{
}
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress, bool premultiply_alpha)
{
m_pData->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart();
unsigned char *pData = (unsigned char *)pHeader + (long)pHeader->idlength + (long)pHeader->colourmaplength * (long)pHeader->colourmaptype + sizeof(TGA_HEADER);
GLenum internal_format = GL_RGBA;
#if !TARGET_OS_IPHONE
if(compress) {
internal_format = pHeader->bitsperpixel == 24 ? GL_COMPRESSED_RGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
#endif
if(pHeader->colourmaptype != 0) {
m_pData->unlock();
return false; // Mapped colors not supported
}
switch(pHeader->imagetype) {
case 2: // rgb
switch(pHeader->bitsperpixel) {
case 24:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
//#ifdef __APPLE__
// vImage_Buffer source_image = { pData, pHeader->height, pHeader->width, pHeader->width*3 };
// vImage_Buffer dest_image = { converted_image, pHeader->height, pHeader->width, pHeader->width*4 };
// vImageConvert_RGB888toRGBA8888(&source_image, NULL, 0xff, &dest_image, false, kvImageDoNotTile);
//#else
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = pData + pHeader->height * pHeader->width * 3;
while(pSource < pEnd) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
pSource += 3;
}
assert(pSource <= m_pData->getEnd());
//#endif
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
case 32:
{
if(premultiply_alpha) {
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = pData + pHeader->height * pHeader->width * 3;
while(pSource < pEnd) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
assert(pSource <= m_pData->getEnd());
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
} else {
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)pData));
GLDEBUG(glFinish());
}
current_lod_max_dim = m_max_lod_max_dim;
}
break;
default:
m_pData->unlock();
return false; // 16-bit images not yet supported
}
break;
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 32:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
if(premultiply_alpha) {
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
} else {
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
pSource += 4;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
}
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
case 24:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
while(pDest < pEnd) {
int count = (*pSource & 0x7f) + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
}
pSource += 3;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
pSource += 3;
}
}
}
assert(pSource <= m_pData->getEnd());
assert(pDest == pEnd);
GLDEBUG(glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image));
GLDEBUG(glFinish());
free(converted_image);
current_lod_max_dim = m_max_lod_max_dim;
}
break;
default:
m_pData->unlock();
return false; // 16-bit images not yet supported
}
break;
default:
m_pData->unlock();
return false; // Image type not yet supported
}
m_pData->unlock();
return true;
}
#if !TARGET_OS_IPHONE
KRTexture *KRTextureTGA::compress(bool premultiply_alpha)
{
m_pData->lock();
std::list<KRDataBlock *> blocks;
getContext().getTextureManager()->_setActiveTexture(0);
GLuint compressed_handle = 0;
GLDEBUG(glGenTextures(1, &compressed_handle));
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle));
int current_max_dim = 0;
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, true, premultiply_alpha)) {
assert(false); // Failed to upload the texture
}
GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D));
GLint width = 0, height = 0, internal_format, base_internal_format;
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format));
/*
int texture_base_level = 0;
int texture_max_level = 0;
GLDEBUG(glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, &texture_base_level));
GLDEBUG(glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, &texture_max_level));
*/
switch(internal_format)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
base_internal_format = GL_BGRA;
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
base_internal_format = GL_BGRA;
break;
default:
assert(false); // Not yet supported
break;
}
GLuint lod_level = 0;
GLint compressed_size = 0;
int lod_width = width;
while(lod_width > 1) {
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, lod_level, GL_TEXTURE_WIDTH, &lod_width));
GLDEBUG(glGetTexLevelParameteriv(GL_TEXTURE_2D, lod_level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressed_size));
KRDataBlock *new_block = new KRDataBlock();
new_block->expand(compressed_size);
new_block->lock();
GLDEBUG(glGetCompressedTexImage(GL_TEXTURE_2D, lod_level, new_block->getStart()));
new_block->unlock();
blocks.push_back(new_block);
lod_level++;
}
assert(lod_width == 1);
GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0));
getContext().getTextureManager()->selectTexture(0, NULL, 0.0f, KRTexture::TEXTURE_USAGE_NONE);
GLDEBUG(glDeleteTextures(1, &compressed_handle));
KRTextureKTX *new_texture = new KRTextureKTX(getContext(), getName(), internal_format, base_internal_format, width, height, blocks);
m_pData->unlock();
for(auto block_itr = blocks.begin(); block_itr != blocks.end(); block_itr++) {
KRDataBlock *block = *block_itr;
delete block;
}
return new_texture;
}
#endif
long KRTextureTGA::getMemRequiredForSize(int max_dim)
{
return m_imageSize;
}
std::string KRTextureTGA::getExtension()
{
return "tga";
}

View File

@@ -1,264 +1,264 @@
//
// KRViewport.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-25.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#define KRENGINE_SWAP_INT(x,y) {int t;t=x;x=y;y=t;}
#include "KREngine-common.h"
#include "KRViewport.h"
KRViewport::KRViewport()
{
m_size = Vector2::One();
m_matProjection = Matrix4();
m_matView = Matrix4();
m_lodBias = 0.0f;
calculateDerivedValues();
}
KRViewport::KRViewport(const Vector2 &size, const Matrix4 &matView, const Matrix4 &matProjection)
{
m_size = size;
m_matView = matView;
m_matProjection = matProjection;
calculateDerivedValues();
}
KRViewport& KRViewport::operator=(const KRViewport &v) {
if(this != &v) { // Prevent self-assignment.
m_size = v.m_size;
m_matProjection = v.m_matProjection;
m_matView = v.m_matView;
m_lodBias = v.m_lodBias;
calculateDerivedValues();
}
return *this;
}
KRViewport::~KRViewport()
{
}
const Vector2 &KRViewport::getSize() const
{
return m_size;
}
const Matrix4 &KRViewport::getViewMatrix() const
{
return m_matView;
}
const Matrix4 &KRViewport::getProjectionMatrix() const
{
return m_matProjection;
}
void KRViewport::setSize(const Vector2 &size)
{
m_size = size;
}
void KRViewport::setViewMatrix(const Matrix4 &matView)
{
m_matView = matView;
calculateDerivedValues();
}
void KRViewport::setProjectionMatrix(const Matrix4 &matProjection)
{
m_matProjection = matProjection;
calculateDerivedValues();
}
const Matrix4 &KRViewport::KRViewport::getViewProjectionMatrix() const
{
return m_matViewProjection;
}
const Matrix4 &KRViewport::getInverseViewMatrix() const
{
return m_matInverseView;
}
const Matrix4 &KRViewport::getInverseProjectionMatrix() const
{
return m_matInverseProjection;
}
const Vector3 &KRViewport::getCameraDirection() const
{
return m_cameraDirection;
}
const Vector3 &KRViewport::getCameraPosition() const
{
return m_cameraPosition;
}
const int *KRViewport::getFrontToBackOrder() const
{
return &m_frontToBackOrder[0];
}
const int *KRViewport::getBackToFrontOrder() const
{
return &m_backToFrontOrder[0];
}
void KRViewport::calculateDerivedValues()
{
m_matViewProjection = m_matView * m_matProjection;
m_matInverseView = Matrix4::Invert(m_matView);
m_matInverseProjection = Matrix4::Invert(m_matProjection);
m_cameraPosition = Matrix4::Dot(m_matInverseView, Vector3::Zero());
m_cameraDirection = Matrix4::Dot(m_matInverseView, Vector3(0.0, 0.0, 1.0)) - Matrix4::Dot(m_matInverseView, Vector3(0.0, 0.0, 0.0));
for(int i=0; i<8; i++) {
m_frontToBackOrder[i] = i;
}
if(m_cameraDirection.x > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[1]);
KRENGINE_SWAP_INT(m_frontToBackOrder[2], m_frontToBackOrder[3]);
KRENGINE_SWAP_INT(m_frontToBackOrder[4], m_frontToBackOrder[5]);
KRENGINE_SWAP_INT(m_frontToBackOrder[6], m_frontToBackOrder[7]);
}
if(m_cameraDirection.y > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[2]);
KRENGINE_SWAP_INT(m_frontToBackOrder[1], m_frontToBackOrder[3]);
KRENGINE_SWAP_INT(m_frontToBackOrder[4], m_frontToBackOrder[6]);
KRENGINE_SWAP_INT(m_frontToBackOrder[5], m_frontToBackOrder[7]);
}
if(m_cameraDirection.z > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[4]);
KRENGINE_SWAP_INT(m_frontToBackOrder[1], m_frontToBackOrder[5]);
KRENGINE_SWAP_INT(m_frontToBackOrder[2], m_frontToBackOrder[6]);
KRENGINE_SWAP_INT(m_frontToBackOrder[3], m_frontToBackOrder[7]);
}
for(int i=0; i<8; i++) {
m_backToFrontOrder[i] = m_frontToBackOrder[7-i];
}
}
unordered_map<AABB, int> &KRViewport::getVisibleBounds()
{
return m_visibleBounds;
}
float KRViewport::getLODBias() const
{
return m_lodBias;
}
void KRViewport::setLODBias(float lod_bias)
{
m_lodBias = lod_bias;
}
float KRViewport::coverage(const AABB &b) const
{
if(!visible(b)) {
return 0.0f; // Culled out by view frustrum
} else {
Vector3 nearest_point = b.nearestPoint(getCameraPosition());
float distance = (nearest_point - getCameraPosition()).magnitude();
Vector3 v = Matrix4::DotWDiv(m_matProjection, getCameraPosition() + getCameraDirection() * distance);
float screen_depth = distance / 1000.0f;
return KRCLAMP(1.0f - screen_depth, 0.01f, 1.0f);
/*
Vector2 screen_min;
Vector2 screen_max;
// Loop through all corners and transform them to screen space
for(int i=0; i<8; i++) {
Vector3 screen_pos = Matrix4::DotWDiv(m_matViewProjection, Vector3(i & 1 ? b.min.x : b.max.x, i & 2 ? b.min.y : b.max.y, i & 4 ? b.min.z : b.max.z));
if(i==0) {
screen_min = screen_pos.xy();
screen_max = screen_pos.xy();
} else {
if(screen_pos.x < screen_min.x) screen_min.x = screen_pos.x;
if(screen_pos.y < screen_min.y) screen_min.y = screen_pos.y;
if(screen_pos.x > screen_max.x) screen_max.x = screen_pos.x;
if(screen_pos.y > screen_max.y) screen_max.y = screen_pos.y;
}
}
screen_min.x = KRCLAMP(screen_min.x, 0.0f, 1.0f);
screen_min.y = KRCLAMP(screen_min.y, 0.0f, 1.0f);
screen_max.x = KRCLAMP(screen_max.x, 0.0f, 1.0f);
screen_max.y = KRCLAMP(screen_max.y, 0.0f, 1.0f);
float c = (screen_max.x - screen_min.x) * (screen_max.y - screen_min.y);
return KRCLAMP(c, 0.01f, 1.0f);
*/
}
}
bool KRViewport::visible(const AABB &b) const
{
// test if bounding box would be within the visible range of the clip space transformed by matViewProjection
// This is used for view frustrum culling
int outside_count[6] = {0, 0, 0, 0, 0, 0};
for(int iCorner=0; iCorner<8; iCorner++) {
Vector4 sourceCornerVertex = Vector4(
(iCorner & 1) == 0 ? b.min.x : b.max.x,
(iCorner & 2) == 0 ? b.min.y : b.max.y,
(iCorner & 4) == 0 ? b.min.z : b.max.z, 1.0f);
Vector4 cornerVertex = Matrix4::Dot4(m_matViewProjection, sourceCornerVertex);
if(cornerVertex.x < -cornerVertex.w) {
outside_count[0]++;
}
if(cornerVertex.y < -cornerVertex.w) {
outside_count[1]++;
}
if(cornerVertex.z < -cornerVertex.w) {
outside_count[2]++;
}
if(cornerVertex.x > cornerVertex.w) {
outside_count[3]++;
}
if(cornerVertex.y > cornerVertex.w) {
outside_count[4]++;
}
if(cornerVertex.z > cornerVertex.w) {
outside_count[5]++;
}
}
bool is_visible = true;
for(int iFace=0; iFace < 6; iFace++) {
if(outside_count[iFace] == 8) {
is_visible = false;
}
}
return is_visible;
}
//
// KRViewport.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-25.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#define KRENGINE_SWAP_INT(x,y) {int t;t=x;x=y;y=t;}
#include "KREngine-common.h"
#include "KRViewport.h"
KRViewport::KRViewport()
{
m_size = Vector2::One();
m_matProjection = Matrix4();
m_matView = Matrix4();
m_lodBias = 0.0f;
calculateDerivedValues();
}
KRViewport::KRViewport(const Vector2 &size, const Matrix4 &matView, const Matrix4 &matProjection)
{
m_size = size;
m_matView = matView;
m_matProjection = matProjection;
calculateDerivedValues();
}
KRViewport& KRViewport::operator=(const KRViewport &v) {
if(this != &v) { // Prevent self-assignment.
m_size = v.m_size;
m_matProjection = v.m_matProjection;
m_matView = v.m_matView;
m_lodBias = v.m_lodBias;
calculateDerivedValues();
}
return *this;
}
KRViewport::~KRViewport()
{
}
const Vector2 &KRViewport::getSize() const
{
return m_size;
}
const Matrix4 &KRViewport::getViewMatrix() const
{
return m_matView;
}
const Matrix4 &KRViewport::getProjectionMatrix() const
{
return m_matProjection;
}
void KRViewport::setSize(const Vector2 &size)
{
m_size = size;
}
void KRViewport::setViewMatrix(const Matrix4 &matView)
{
m_matView = matView;
calculateDerivedValues();
}
void KRViewport::setProjectionMatrix(const Matrix4 &matProjection)
{
m_matProjection = matProjection;
calculateDerivedValues();
}
const Matrix4 &KRViewport::KRViewport::getViewProjectionMatrix() const
{
return m_matViewProjection;
}
const Matrix4 &KRViewport::getInverseViewMatrix() const
{
return m_matInverseView;
}
const Matrix4 &KRViewport::getInverseProjectionMatrix() const
{
return m_matInverseProjection;
}
const Vector3 &KRViewport::getCameraDirection() const
{
return m_cameraDirection;
}
const Vector3 &KRViewport::getCameraPosition() const
{
return m_cameraPosition;
}
const int *KRViewport::getFrontToBackOrder() const
{
return &m_frontToBackOrder[0];
}
const int *KRViewport::getBackToFrontOrder() const
{
return &m_backToFrontOrder[0];
}
void KRViewport::calculateDerivedValues()
{
m_matViewProjection = m_matView * m_matProjection;
m_matInverseView = Matrix4::Invert(m_matView);
m_matInverseProjection = Matrix4::Invert(m_matProjection);
m_cameraPosition = Matrix4::Dot(m_matInverseView, Vector3::Zero());
m_cameraDirection = Matrix4::Dot(m_matInverseView, Vector3::Create(0.0, 0.0, 1.0)) - Matrix4::Dot(m_matInverseView, Vector3::Create(0.0, 0.0, 0.0));
for(int i=0; i<8; i++) {
m_frontToBackOrder[i] = i;
}
if(m_cameraDirection.x > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[1]);
KRENGINE_SWAP_INT(m_frontToBackOrder[2], m_frontToBackOrder[3]);
KRENGINE_SWAP_INT(m_frontToBackOrder[4], m_frontToBackOrder[5]);
KRENGINE_SWAP_INT(m_frontToBackOrder[6], m_frontToBackOrder[7]);
}
if(m_cameraDirection.y > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[2]);
KRENGINE_SWAP_INT(m_frontToBackOrder[1], m_frontToBackOrder[3]);
KRENGINE_SWAP_INT(m_frontToBackOrder[4], m_frontToBackOrder[6]);
KRENGINE_SWAP_INT(m_frontToBackOrder[5], m_frontToBackOrder[7]);
}
if(m_cameraDirection.z > 0.0) {
KRENGINE_SWAP_INT(m_frontToBackOrder[0], m_frontToBackOrder[4]);
KRENGINE_SWAP_INT(m_frontToBackOrder[1], m_frontToBackOrder[5]);
KRENGINE_SWAP_INT(m_frontToBackOrder[2], m_frontToBackOrder[6]);
KRENGINE_SWAP_INT(m_frontToBackOrder[3], m_frontToBackOrder[7]);
}
for(int i=0; i<8; i++) {
m_backToFrontOrder[i] = m_frontToBackOrder[7-i];
}
}
unordered_map<AABB, int> &KRViewport::getVisibleBounds()
{
return m_visibleBounds;
}
float KRViewport::getLODBias() const
{
return m_lodBias;
}
void KRViewport::setLODBias(float lod_bias)
{
m_lodBias = lod_bias;
}
float KRViewport::coverage(const AABB &b) const
{
if(!visible(b)) {
return 0.0f; // Culled out by view frustrum
} else {
Vector3 nearest_point = b.nearestPoint(getCameraPosition());
float distance = (nearest_point - getCameraPosition()).magnitude();
Vector3 v = Matrix4::DotWDiv(m_matProjection, getCameraPosition() + getCameraDirection() * distance);
float screen_depth = distance / 1000.0f;
return KRCLAMP(1.0f - screen_depth, 0.01f, 1.0f);
/*
Vector2 screen_min;
Vector2 screen_max;
// Loop through all corners and transform them to screen space
for(int i=0; i<8; i++) {
Vector3 screen_pos = Matrix4::DotWDiv(m_matViewProjection, Vector3(i & 1 ? b.min.x : b.max.x, i & 2 ? b.min.y : b.max.y, i & 4 ? b.min.z : b.max.z));
if(i==0) {
screen_min = screen_pos.xy();
screen_max = screen_pos.xy();
} else {
if(screen_pos.x < screen_min.x) screen_min.x = screen_pos.x;
if(screen_pos.y < screen_min.y) screen_min.y = screen_pos.y;
if(screen_pos.x > screen_max.x) screen_max.x = screen_pos.x;
if(screen_pos.y > screen_max.y) screen_max.y = screen_pos.y;
}
}
screen_min.x = KRCLAMP(screen_min.x, 0.0f, 1.0f);
screen_min.y = KRCLAMP(screen_min.y, 0.0f, 1.0f);
screen_max.x = KRCLAMP(screen_max.x, 0.0f, 1.0f);
screen_max.y = KRCLAMP(screen_max.y, 0.0f, 1.0f);
float c = (screen_max.x - screen_min.x) * (screen_max.y - screen_min.y);
return KRCLAMP(c, 0.01f, 1.0f);
*/
}
}
bool KRViewport::visible(const AABB &b) const
{
// test if bounding box would be within the visible range of the clip space transformed by matViewProjection
// This is used for view frustrum culling
int outside_count[6] = {0, 0, 0, 0, 0, 0};
for(int iCorner=0; iCorner<8; iCorner++) {
Vector4 sourceCornerVertex = Vector4::Create(
(iCorner & 1) == 0 ? b.min.x : b.max.x,
(iCorner & 2) == 0 ? b.min.y : b.max.y,
(iCorner & 4) == 0 ? b.min.z : b.max.z, 1.0f);
Vector4 cornerVertex = Matrix4::Dot4(m_matViewProjection, sourceCornerVertex);
if(cornerVertex.x < -cornerVertex.w) {
outside_count[0]++;
}
if(cornerVertex.y < -cornerVertex.w) {
outside_count[1]++;
}
if(cornerVertex.z < -cornerVertex.w) {
outside_count[2]++;
}
if(cornerVertex.x > cornerVertex.w) {
outside_count[3]++;
}
if(cornerVertex.y > cornerVertex.w) {
outside_count[4]++;
}
if(cornerVertex.z > cornerVertex.w) {
outside_count[5]++;
}
}
bool is_visible = true;
for(int iFace=0; iFace < 6; iFace++) {
if(outside_count[iFace] == 8) {
is_visible = false;
}
}
return is_visible;
}

View File

@@ -1,73 +1,75 @@
//
// KRViewport.h
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-25.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#ifndef KRENGINE_KRVIEWPORT_H
#define KRENGINE_KRVIEWPORT_H
#include "KREngine-common.h"
class KRLight;
class KRViewport {
public:
KRViewport();
KRViewport(const Vector2 &size, const Matrix4 &matView, const Matrix4 &matProjection);
~KRViewport();
const Vector2 &getSize() const;
const Matrix4 &getViewMatrix() const;
const Matrix4 &getProjectionMatrix() const;
const Matrix4 &getViewProjectionMatrix() const;
const Matrix4 &getInverseViewMatrix() const;
const Matrix4 &getInverseProjectionMatrix() const;
const Vector3 &getCameraDirection() const;
const Vector3 &getCameraPosition() const;
const int *getFrontToBackOrder() const;
const int *getBackToFrontOrder() const;
void setSize(const Vector2 &size);
void setViewMatrix(const Matrix4 &matView);
void setProjectionMatrix(const Matrix4 &matProjection);
float getLODBias() const;
void setLODBias(float lod_bias);
// Overload assignment operator
KRViewport& operator=(const KRViewport &v);
unordered_map<AABB, int> &getVisibleBounds();
const std::set<KRLight *> &getVisibleLights();
void setVisibleLights(const std::set<KRLight *> visibleLights);
bool visible(const AABB &b) const;
float coverage(const AABB &b) const;
private:
Vector2 m_size;
Matrix4 m_matView;
Matrix4 m_matProjection;
float m_lodBias;
// Derived values
Matrix4 m_matViewProjection;
Matrix4 m_matInverseView;
Matrix4 m_matInverseProjection;
Vector3 m_cameraDirection;
Vector3 m_cameraPosition;
int m_frontToBackOrder[8];
int m_backToFrontOrder[8];
void calculateDerivedValues();
unordered_map<AABB, int> m_visibleBounds; // AABB's that output fragments in the last frame
};
#endif
//
// KRViewport.h
// KREngine
//
// Created by Kearwood Gilbert on 2012-10-25.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#ifndef KRENGINE_KRVIEWPORT_H
#define KRENGINE_KRVIEWPORT_H
#include "KREngine-common.h"
#include "aabb.h"
class KRLight;
class KRViewport {
public:
KRViewport();
KRViewport(const Vector2 &size, const Matrix4 &matView, const Matrix4 &matProjection);
~KRViewport();
const Vector2 &getSize() const;
const Matrix4 &getViewMatrix() const;
const Matrix4 &getProjectionMatrix() const;
const Matrix4 &getViewProjectionMatrix() const;
const Matrix4 &getInverseViewMatrix() const;
const Matrix4 &getInverseProjectionMatrix() const;
const Vector3 &getCameraDirection() const;
const Vector3 &getCameraPosition() const;
const int *getFrontToBackOrder() const;
const int *getBackToFrontOrder() const;
void setSize(const Vector2 &size);
void setViewMatrix(const Matrix4 &matView);
void setProjectionMatrix(const Matrix4 &matProjection);
float getLODBias() const;
void setLODBias(float lod_bias);
// Overload assignment operator
KRViewport& operator=(const KRViewport &v);
unordered_map<AABB, int> &getVisibleBounds();
const std::set<KRLight *> &getVisibleLights();
void setVisibleLights(const std::set<KRLight *> visibleLights);
bool visible(const AABB &b) const;
float coverage(const AABB &b) const;
private:
Vector2 m_size;
Matrix4 m_matView;
Matrix4 m_matProjection;
float m_lodBias;
// Derived values
Matrix4 m_matViewProjection;
Matrix4 m_matInverseView;
Matrix4 m_matInverseProjection;
Vector3 m_cameraDirection;
Vector3 m_cameraPosition;
int m_frontToBackOrder[8];
int m_backToFrontOrder[8];
void calculateDerivedValues();
unordered_map<AABB, int> m_visibleBounds; // AABB's that output fragments in the last frame
};
#endif

View File

@@ -1,339 +0,0 @@
//
// KRAABB.cpp
// KREngine
//
// Created by Kearwood Gilbert on 2012-08-30.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
#include "assert.h"
#include "KRHelpers.h"
namespace kraken {
AABB::AABB()
{
min = Vector3::Min();
max = Vector3::Max();
}
AABB::AABB(const Vector3 &minPoint, const Vector3 &maxPoint)
{
min = minPoint;
max = maxPoint;
}
AABB::AABB(const Vector3 &corner1, const Vector3 &corner2, const Matrix4 &modelMatrix)
{
for(int iCorner=0; iCorner<8; iCorner++) {
Vector3 sourceCornerVertex = Matrix4::DotWDiv(modelMatrix, Vector3(
(iCorner & 1) == 0 ? corner1.x : corner2.x,
(iCorner & 2) == 0 ? corner1.y : corner2.y,
(iCorner & 4) == 0 ? corner1.z : corner2.z));
if(iCorner == 0) {
min = sourceCornerVertex;
max = sourceCornerVertex;
} else {
if(sourceCornerVertex.x < min.x) min.x = sourceCornerVertex.x;
if(sourceCornerVertex.y < min.y) min.y = sourceCornerVertex.y;
if(sourceCornerVertex.z < min.z) min.z = sourceCornerVertex.z;
if(sourceCornerVertex.x > max.x) max.x = sourceCornerVertex.x;
if(sourceCornerVertex.y > max.y) max.y = sourceCornerVertex.y;
if(sourceCornerVertex.z > max.z) max.z = sourceCornerVertex.z;
}
}
}
AABB::~AABB()
{
}
AABB& AABB::operator =(const AABB& b)
{
min = b.min;
max = b.max;
return *this;
}
bool AABB::operator ==(const AABB& b) const
{
return min == b.min && max == b.max;
}
bool AABB::operator !=(const AABB& b) const
{
return min != b.min || max != b.max;
}
Vector3 AABB::center() const
{
return (min + max) * 0.5f;
}
Vector3 AABB::size() const
{
return max - min;
}
float AABB::volume() const
{
Vector3 s = size();
return s.x * s.y * s.z;
}
void AABB::scale(const Vector3 &s)
{
Vector3 prev_center = center();
Vector3 prev_size = size();
Vector3 new_scale = Vector3(prev_size.x * s.x, prev_size.y * s.y, prev_size.z * s.z) * 0.5f;
min = prev_center - new_scale;
max = prev_center + new_scale;
}
void AABB::scale(float s)
{
scale(Vector3(s));
}
bool AABB::operator >(const AABB& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(min > b.min) {
return true;
} else if(min < b.min) {
return false;
} else if(max > b.max) {
return true;
} else {
return false;
}
}
bool AABB::operator <(const AABB& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(min < b.min) {
return true;
} else if(min > b.min) {
return false;
} else if(max < b.max) {
return true;
} else {
return false;
}
}
bool AABB::intersects(const AABB& b) const
{
// Return true if the two volumes intersect
return min.x <= b.max.x && min.y <= b.max.y && min.z <= b.max.z && max.x >= b.min.x && max.y >= b.min.y && max.z >= b.min.z;
}
bool AABB::contains(const AABB &b) const
{
// Return true if the passed KRAABB is entirely contained within this KRAABB
return b.min.x >= min.x && b.min.y >= min.y && b.min.z >= min.z && b.max.x <= max.x && b.max.y <= max.y && b.max.z <= max.z;
}
bool AABB::contains(const Vector3 &v) const
{
return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.y && v.z >= min.z && v.z <= max.z;
}
AABB AABB::Infinite()
{
return AABB(Vector3::Min(), Vector3::Max());
}
AABB AABB::Zero()
{
return AABB(Vector3::Zero(), Vector3::Zero());
}
float AABB::longest_radius() const
{
float radius1 = (center() - min).magnitude();
float radius2 = (max - center()).magnitude();
return radius1 > radius2 ? radius1 : radius2;
}
bool AABB::intersectsLine(const Vector3 &v1, const Vector3 &v2) const
{
Vector3 dir = Vector3::Normalize(v2 - v1);
float length = (v2 - v1).magnitude();
// EZ cases: if the ray starts inside the box, or ends inside
// the box, then it definitely hits the box.
// I'm using this code for ray tracing with an octree,
// so I needed rays that start and end within an
// octree node to COUNT as hits.
// You could modify this test to (ray starts inside and ends outside)
// to qualify as a hit if you wanted to NOT count totally internal rays
if( contains( v1 ) || contains( v2 ) )
return true ;
// the algorithm says, find 3 t's,
Vector3 t ;
// LARGEST t is the only one we need to test if it's on the face.
for(int i = 0 ; i < 3 ; i++) {
if( dir[i] > 0 ) { // CULL BACK FACE
t[i] = ( min[i] - v1[i] ) / dir[i];
} else {
t[i] = ( max[i] - v1[i] ) / dir[i];
}
}
int mi = 0;
if(t[1] > t[mi]) mi = 1;
if(t[2] > t[mi]) mi = 2;
if(t[mi] >= 0 && t[mi] <= length) {
Vector3 pt = v1 + dir * t[mi];
// check it's in the box in other 2 dimensions
int o1 = ( mi + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
int o2 = ( mi + 2 ) % 3 ;
return pt[o1] >= min[o1] && pt[o1] <= max[o1] && pt[o2] >= min[o2] && pt[o2] <= max[o2];
}
return false ; // the ray did not hit the box.
}
bool AABB::intersectsRay(const Vector3 &v1, const Vector3 &dir) const
{
/*
Fast Ray-Box Intersection
by Andrew Woo
from "Graphics Gems", Academic Press, 1990
*/
// FINDME, TODO - Perhaps there is a more efficient algorithm, as we don't actually need the exact coordinate of the intersection
enum {
RIGHT = 0,
LEFT = 1,
MIDDLE = 2
} quadrant[3];
bool inside = true;
Vector3 maxT;
Vector3 coord;
double candidatePlane[3];
// Find candidate planes; this loop can be avoided if rays cast all from the eye(assume perpsective view)
for (int i=0; i<3; i++)
if(v1.c[i] < min.c[i]) {
quadrant[i] = LEFT;
candidatePlane[i] = min.c[i];
inside = false;
} else if(v1.c[i] > max.c[i]) {
quadrant[i] = RIGHT;
candidatePlane[i] = max.c[i];
inside = false;
} else {
quadrant[i] = MIDDLE;
}
/* Ray v1 inside bounding box */
if (inside) {
coord = v1;
return true;
}
/* Calculate T distances to candidate planes */
for (int i = 0; i < 3; i++) {
if (quadrant[i] != MIDDLE && dir[i] != 0.0f) {
maxT.c[i] = (candidatePlane[i]-v1.c[i]) / dir[i];
} else {
maxT.c[i] = -1.0f;
}
}
/* Get largest of the maxT's for final choice of intersection */
int whichPlane = 0;
for (int i = 1; i < 3; i++) {
if (maxT.c[whichPlane] < maxT.c[i]) {
whichPlane = i;
}
}
/* Check final candidate actually inside box */
if (maxT.c[whichPlane] < 0.0f) {
return false;
}
for (int i = 0; i < 3; i++) {
if (whichPlane != i) {
coord[i] = v1.c[i] + maxT.c[whichPlane] *dir[i];
if (coord[i] < min.c[i] || coord[i] > max.c[i]) {
return false;
}
} else {
assert(quadrant[i] != MIDDLE); // This should not be possible
coord[i] = candidatePlane[i];
}
}
return true; /* ray hits box */
}
bool AABB::intersectsSphere(const Vector3 &center, float radius) const
{
// Arvo's Algorithm
float squaredDistance = 0;
// process X
if (center.x < min.x) {
float diff = center.x - min.x;
squaredDistance += diff * diff;
} else if (center.x > max.x) {
float diff = center.x - max.x;
squaredDistance += diff * diff;
}
// process Y
if (center.y < min.y) {
float diff = center.y - min.y;
squaredDistance += diff * diff;
} else if (center.y > max.y) {
float diff = center.y - max.y;
squaredDistance += diff * diff;
}
// process Z
if (center.z < min.z) {
float diff = center.z - min.z;
squaredDistance += diff * diff;
} else if (center.z > max.z) {
float diff = center.z - max.z;
squaredDistance += diff * diff;
}
return squaredDistance <= radius;
}
void AABB::encapsulate(const AABB & b)
{
if(b.min.x < min.x) min.x = b.min.x;
if(b.min.y < min.y) min.y = b.min.y;
if(b.min.z < min.z) min.z = b.min.z;
if(b.max.x > max.x) max.x = b.max.x;
if(b.max.y > max.y) max.y = b.max.y;
if(b.max.z > max.z) max.z = b.max.z;
}
Vector3 AABB::nearestPoint(const Vector3 & v) const
{
return Vector3(KRCLAMP(v.x, min.x, max.x), KRCLAMP(v.y, min.y, max.y), KRCLAMP(v.z, min.z, max.z));
}
} // namespace kraken

View File

@@ -1,100 +0,0 @@
//
// HitInfo.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.
//
#include "public/kraken.h"
namespace kraken {
HitInfo::HitInfo()
{
m_position = Vector3::Zero();
m_normal = Vector3::Zero();
m_distance = 0.0f;
m_node = NULL;
}
HitInfo::HitInfo(const Vector3 &position, const Vector3 &normal, const float distance, KRNode *node)
{
m_position = position;
m_normal = normal;
m_distance = distance;
m_node = node;
}
HitInfo::HitInfo(const Vector3 &position, const Vector3 &normal, const float distance)
{
m_position = position;
m_normal = normal;
m_distance = distance;
m_node = NULL;
}
HitInfo::~HitInfo()
{
}
bool HitInfo::didHit() const
{
return m_normal != Vector3::Zero();
}
Vector3 HitInfo::getPosition() const
{
return m_position;
}
Vector3 HitInfo::getNormal() const
{
return m_normal;
}
float HitInfo::getDistance() const
{
return m_distance;
}
KRNode *HitInfo::getNode() const
{
return m_node;
}
HitInfo& HitInfo::operator =(const HitInfo& b)
{
m_position = b.m_position;
m_normal = b.m_normal;
m_distance = b.m_distance;
m_node = b.m_node;
return *this;
}
} // namespace kraken

View File

@@ -1,448 +0,0 @@
//
// Matrix4.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.
//
#include "public/kraken.h"
#include <string.h>
namespace kraken {
Matrix4::Matrix4() {
// Default constructor - Initialize with an identity matrix
static const float IDENTITY_MATRIX[] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
memcpy(c, IDENTITY_MATRIX, sizeof(float) * 16);
}
Matrix4::Matrix4(float *pMat) {
memcpy(c, pMat, sizeof(float) * 16);
}
Matrix4::Matrix4(const Vector3 &new_axis_x, const Vector3 &new_axis_y, const Vector3 &new_axis_z, const Vector3 &new_transform)
{
c[0] = new_axis_x.x; c[1] = new_axis_x.y; c[2] = new_axis_x.z; c[3] = 0.0f;
c[4] = new_axis_y.x; c[5] = new_axis_y.y; c[6] = new_axis_y.z; c[7] = 0.0f;
c[8] = new_axis_z.x; c[9] = new_axis_z.y; c[10] = new_axis_z.z; c[11] = 0.0f;
c[12] = new_transform.x; c[13] = new_transform.y; c[14] = new_transform.z; c[15] = 1.0f;
}
Matrix4::~Matrix4() {
}
float *Matrix4::getPointer() {
return c;
}
// Copy constructor
Matrix4::Matrix4(const Matrix4 &m) {
memcpy(c, m.c, sizeof(float) * 16);
}
Matrix4& Matrix4::operator=(const Matrix4 &m) {
if(this != &m) { // Prevent self-assignment.
memcpy(c, m.c, sizeof(float) * 16);
}
return *this;
}
float& Matrix4::operator[](unsigned i) {
return c[i];
}
float Matrix4::operator[](unsigned i) const {
return c[i];
}
// Overload comparison operator
bool Matrix4::operator==(const Matrix4 &m) const {
return memcmp(c, m.c, sizeof(float) * 16) == 0;
}
// Overload compound multiply operator
Matrix4& Matrix4::operator*=(const Matrix4 &m) {
float temp[16];
int x,y;
for (x=0; x < 4; x++)
{
for(y=0; y < 4; y++)
{
temp[y + (x*4)] = (c[x*4] * m.c[y]) +
(c[(x*4)+1] * m.c[y+4]) +
(c[(x*4)+2] * m.c[y+8]) +
(c[(x*4)+3] * m.c[y+12]);
}
}
memcpy(c, temp, sizeof(float) << 4);
return *this;
}
// Overload multiply operator
Matrix4 Matrix4::operator*(const Matrix4 &m) const {
Matrix4 ret = *this;
ret *= m;
return ret;
}
/* Generate a perspective view matrix using a field of view angle fov,
* window aspect ratio, near and far clipping planes */
void Matrix4::perspective(float fov, float aspect, float nearz, float farz) {
memset(c, 0, sizeof(float) * 16);
float range= tan(fov * 0.5) * nearz;
c[0] = (2 * nearz) / ((range * aspect) - (-range * aspect));
c[5] = (2 * nearz) / (2 * range);
c[10] = -(farz + nearz) / (farz - nearz);
c[11] = -1;
c[14] = -(2 * farz * nearz) / (farz - nearz);
/*
float range= atan(fov / 20.0f) * nearz;
float r = range * aspect;
float t = range * 1.0;
c[0] = nearz / r;
c[5] = nearz / t;
c[10] = -(farz + nearz) / (farz - nearz);
c[11] = -(2.0 * farz * nearz) / (farz - nearz);
c[14] = -1.0;
*/
}
/* Perform translation operations on a matrix */
void Matrix4::translate(float x, float y, float z) {
Matrix4 newMatrix; // Create new identity matrix
newMatrix.c[12] = x;
newMatrix.c[13] = y;
newMatrix.c[14] = z;
*this *= newMatrix;
}
void Matrix4::translate(const Vector3 &v)
{
translate(v.x, v.y, v.z);
}
/* Rotate a matrix by an angle on a X, Y, or Z axis */
void Matrix4::rotate(float angle, AXIS axis) {
const int cos1[3] = { 5, 0, 0 }; // cos(angle)
const int cos2[3] = { 10, 10, 5 }; // cos(angle)
const int sin1[3] = { 9, 2, 4 }; // -sin(angle)
const int sin2[3] = { 6, 8, 1 }; // sin(angle)
/*
X_AXIS:
1, 0, 0, 0
0, cos(angle), -sin(angle), 0
0, sin(angle), cos(angle), 0
0, 0, 0, 1
Y_AXIS:
cos(angle), 0, -sin(angle), 0
0, 1, 0, 0
sin(angle), 0, cos(angle), 0
0, 0, 0, 1
Z_AXIS:
cos(angle), -sin(angle), 0, 0
sin(angle), cos(angle), 0, 0
0, 0, 1, 0
0, 0, 0, 1
*/
Matrix4 newMatrix; // Create new identity matrix
newMatrix.c[cos1[axis]] = cos(angle);
newMatrix.c[sin1[axis]] = -sin(angle);
newMatrix.c[sin2[axis]] = -newMatrix.c[sin1[axis]];
newMatrix.c[cos2[axis]] = newMatrix.c[cos1[axis]];
*this *= newMatrix;
}
void Matrix4::rotate(const Quaternion &q)
{
*this *= q.rotationMatrix();
}
/* Scale matrix by separate x, y, and z amounts */
void Matrix4::scale(float x, float y, float z) {
Matrix4 newMatrix; // Create new identity matrix
newMatrix.c[0] = x;
newMatrix.c[5] = y;
newMatrix.c[10] = z;
*this *= newMatrix;
}
void Matrix4::scale(const Vector3 &v) {
scale(v.x, v.y, v.z);
}
/* Scale all dimensions equally */
void Matrix4::scale(float s) {
scale(s,s,s);
}
// Initialize with a bias matrix
void Matrix4::bias() {
static const float BIAS_MATRIX[] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
};
memcpy(c, BIAS_MATRIX, sizeof(float) * 16);
}
/* Generate an orthographic view matrix */
void Matrix4::ortho(float left, float right, float top, float bottom, float nearz, float farz) {
memset(c, 0, sizeof(float) * 16);
c[0] = 2.0f / (right - left);
c[5] = 2.0f / (bottom - top);
c[10] = -1.0f / (farz - nearz);
c[11] = -nearz / (farz - nearz);
c[15] = 1.0f;
}
/* Replace matrix with its inverse */
bool Matrix4::invert() {
// Based on gluInvertMatrix implementation
float inv[16], det;
int i;
inv[0] = c[5]*c[10]*c[15] - c[5]*c[11]*c[14] - c[9]*c[6]*c[15]
+ c[9]*c[7]*c[14] + c[13]*c[6]*c[11] - c[13]*c[7]*c[10];
inv[4] = -c[4]*c[10]*c[15] + c[4]*c[11]*c[14] + c[8]*c[6]*c[15]
- c[8]*c[7]*c[14] - c[12]*c[6]*c[11] + c[12]*c[7]*c[10];
inv[8] = c[4]*c[9]*c[15] - c[4]*c[11]*c[13] - c[8]*c[5]*c[15]
+ c[8]*c[7]*c[13] + c[12]*c[5]*c[11] - c[12]*c[7]*c[9];
inv[12] = -c[4]*c[9]*c[14] + c[4]*c[10]*c[13] + c[8]*c[5]*c[14]
- c[8]*c[6]*c[13] - c[12]*c[5]*c[10] + c[12]*c[6]*c[9];
inv[1] = -c[1]*c[10]*c[15] + c[1]*c[11]*c[14] + c[9]*c[2]*c[15]
- c[9]*c[3]*c[14] - c[13]*c[2]*c[11] + c[13]*c[3]*c[10];
inv[5] = c[0]*c[10]*c[15] - c[0]*c[11]*c[14] - c[8]*c[2]*c[15]
+ c[8]*c[3]*c[14] + c[12]*c[2]*c[11] - c[12]*c[3]*c[10];
inv[9] = -c[0]*c[9]*c[15] + c[0]*c[11]*c[13] + c[8]*c[1]*c[15]
- c[8]*c[3]*c[13] - c[12]*c[1]*c[11] + c[12]*c[3]*c[9];
inv[13] = c[0]*c[9]*c[14] - c[0]*c[10]*c[13] - c[8]*c[1]*c[14]
+ c[8]*c[2]*c[13] + c[12]*c[1]*c[10] - c[12]*c[2]*c[9];
inv[2] = c[1]*c[6]*c[15] - c[1]*c[7]*c[14] - c[5]*c[2]*c[15]
+ c[5]*c[3]*c[14] + c[13]*c[2]*c[7] - c[13]*c[3]*c[6];
inv[6] = -c[0]*c[6]*c[15] + c[0]*c[7]*c[14] + c[4]*c[2]*c[15]
- c[4]*c[3]*c[14] - c[12]*c[2]*c[7] + c[12]*c[3]*c[6];
inv[10] = c[0]*c[5]*c[15] - c[0]*c[7]*c[13] - c[4]*c[1]*c[15]
+ c[4]*c[3]*c[13] + c[12]*c[1]*c[7] - c[12]*c[3]*c[5];
inv[14] = -c[0]*c[5]*c[14] + c[0]*c[6]*c[13] + c[4]*c[1]*c[14]
- c[4]*c[2]*c[13] - c[12]*c[1]*c[6] + c[12]*c[2]*c[5];
inv[3] = -c[1]*c[6]*c[11] + c[1]*c[7]*c[10] + c[5]*c[2]*c[11]
- c[5]*c[3]*c[10] - c[9]*c[2]*c[7] + c[9]*c[3]*c[6];
inv[7] = c[0]*c[6]*c[11] - c[0]*c[7]*c[10] - c[4]*c[2]*c[11]
+ c[4]*c[3]*c[10] + c[8]*c[2]*c[7] - c[8]*c[3]*c[6];
inv[11] = -c[0]*c[5]*c[11] + c[0]*c[7]*c[9] + c[4]*c[1]*c[11]
- c[4]*c[3]*c[9] - c[8]*c[1]*c[7] + c[8]*c[3]*c[5];
inv[15] = c[0]*c[5]*c[10] - c[0]*c[6]*c[9] - c[4]*c[1]*c[10]
+ c[4]*c[2]*c[9] + c[8]*c[1]*c[6] - c[8]*c[2]*c[5];
det = c[0]*inv[0] + c[1]*inv[4] + c[2]*inv[8] + c[3]*inv[12];
if (det == 0) {
return false;
}
det = 1.0 / det;
for (i = 0; i < 16; i++) {
c[i] = inv[i] * det;
}
return true;
}
void Matrix4::transpose() {
float trans[16];
for(int x=0; x<4; x++) {
for(int y=0; y<4; y++) {
trans[x + y * 4] = c[y + x * 4];
}
}
memcpy(c, trans, sizeof(float) * 16);
}
/* Dot Product, returning Vector3 */
Vector3 Matrix4::Dot(const Matrix4 &m, const Vector3 &v) {
return Vector3(
v.c[0] * m.c[0] + v.c[1] * m.c[4] + v.c[2] * m.c[8] + m.c[12],
v.c[0] * m.c[1] + v.c[1] * m.c[5] + v.c[2] * m.c[9] + m.c[13],
v.c[0] * m.c[2] + v.c[1] * m.c[6] + v.c[2] * m.c[10] + m.c[14]
);
}
Vector4 Matrix4::Dot4(const Matrix4 &m, const Vector4 &v) {
#ifdef KRAKEN_USE_ARM_NEON
Vector4 d;
asm volatile (
"vld1.32 {d0, d1}, [%1] \n\t" //Q0 = v
"vld1.32 {d18, d19}, [%0]! \n\t" //Q1 = m
"vld1.32 {d20, d21}, [%0]! \n\t" //Q2 = m+4
"vld1.32 {d22, d23}, [%0]! \n\t" //Q3 = m+8
"vld1.32 {d24, d25}, [%0]! \n\t" //Q4 = m+12
"vmul.f32 q13, q9, d0[0] \n\t" //Q5 = Q1*Q0[0]
"vmla.f32 q13, q10, d0[1] \n\t" //Q5 += Q1*Q0[1]
"vmla.f32 q13, q11, d1[0] \n\t" //Q5 += Q2*Q0[2]
"vmla.f32 q13, q12, d1[1] \n\t" //Q5 += Q3*Q0[3]
"vst1.32 {d26, d27}, [%2] \n\t" //Q4 = m+12
: /* no output registers */
: "r"(m.c), "r"(v.c), "r"(d.c)
: "q0", "q9", "q10","q11", "q12", "q13", "memory"
);
return d;
#else
return Vector4(
v.c[0] * m.c[0] + v.c[1] * m.c[4] + v.c[2] * m.c[8] + m.c[12],
v.c[0] * m.c[1] + v.c[1] * m.c[5] + v.c[2] * m.c[9] + m.c[13],
v.c[0] * m.c[2] + v.c[1] * m.c[6] + v.c[2] * m.c[10] + m.c[14],
v.c[0] * m.c[3] + v.c[1] * m.c[7] + v.c[2] * m.c[11] + m.c[15]
);
#endif
}
// Dot product without including translation; useful for transforming normals and tangents
Vector3 Matrix4::DotNoTranslate(const Matrix4 &m, const Vector3 &v)
{
return Vector3(
v.x * m.c[0] + v.y * m.c[4] + v.z * m.c[8],
v.x * m.c[1] + v.y * m.c[5] + v.z * m.c[9],
v.x * m.c[2] + v.y * m.c[6] + v.z * m.c[10]
);
}
/* Dot Product, returning w component as if it were a Vector4 (This will be deprecated once Vector4 is implemented instead*/
float Matrix4::DotW(const Matrix4 &m, const Vector3 &v) {
return v.x * m.c[0*4 + 3] + v.y * m.c[1*4 + 3] + v.z * m.c[2*4 + 3] + m.c[3*4 + 3];
}
/* Dot Product followed by W-divide */
Vector3 Matrix4::DotWDiv(const Matrix4 &m, const Vector3 &v) {
Vector4 r = Dot4(m, Vector4(v, 1.0f));
return Vector3(r) / r.w;
}
Matrix4 Matrix4::LookAt(const Vector3 &cameraPos, const Vector3 &lookAtPos, const Vector3 &upDirection)
{
Matrix4 matLookat;
Vector3 lookat_z_axis = lookAtPos - cameraPos;
lookat_z_axis.normalize();
Vector3 lookat_x_axis = Vector3::Cross(upDirection, lookat_z_axis);
lookat_x_axis.normalize();
Vector3 lookat_y_axis = Vector3::Cross(lookat_z_axis, lookat_x_axis);
matLookat.getPointer()[0] = lookat_x_axis.x;
matLookat.getPointer()[1] = lookat_y_axis.x;
matLookat.getPointer()[2] = lookat_z_axis.x;
matLookat.getPointer()[4] = lookat_x_axis.y;
matLookat.getPointer()[5] = lookat_y_axis.y;
matLookat.getPointer()[6] = lookat_z_axis.y;
matLookat.getPointer()[8] = lookat_x_axis.z;
matLookat.getPointer()[9] = lookat_y_axis.z;
matLookat.getPointer()[10] = lookat_z_axis.z;
matLookat.getPointer()[12] = -Vector3::Dot(lookat_x_axis, cameraPos);
matLookat.getPointer()[13] = -Vector3::Dot(lookat_y_axis, cameraPos);
matLookat.getPointer()[14] = -Vector3::Dot(lookat_z_axis, cameraPos);
return matLookat;
}
Matrix4 Matrix4::Invert(const Matrix4 &m)
{
Matrix4 matInvert = m;
matInvert.invert();
return matInvert;
}
Matrix4 Matrix4::Transpose(const Matrix4 &m)
{
Matrix4 matTranspose = m;
matTranspose.transpose();
return matTranspose;
}
Matrix4 Matrix4::Translation(const Vector3 &v)
{
Matrix4 m;
m[12] = v.x;
m[13] = v.y;
m[14] = v.z;
// m.translate(v);
return m;
}
Matrix4 Matrix4::Rotation(const Vector3 &v)
{
Matrix4 m;
m.rotate(v.x, X_AXIS);
m.rotate(v.y, Y_AXIS);
m.rotate(v.z, Z_AXIS);
return m;
}
Matrix4 Matrix4::Scaling(const Vector3 &v)
{
Matrix4 m;
m.scale(v);
return m;
}
} // namespace kraken

View File

@@ -1,11 +1,2 @@
add_public_header(kraken.h)
add_public_header(scalar.h)
add_public_header(vector2.h)
add_public_header(vector3.h)
add_public_header(vector4.h)
add_public_header(triangle3.h)
add_public_header(quaternion.h)
add_public_header(aabb.h)
add_public_header(matrix4.h)
add_public_header(hitinfo.h)
set(KRAKEN_PUBLIC_HEADERS "${KRAKEN_PUBLIC_HEADERS}" PARENT_SCOPE)
add_public_header(kraken.h)
set(KRAKEN_PUBLIC_HEADERS "${KRAKEN_PUBLIC_HEADERS}" PARENT_SCOPE)

View File

@@ -1,102 +0,0 @@
//
// KRAABB.h
// Kraken
//
// Copyright 2018 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.
//
// Axis aligned bounding box (AABB)
#ifndef KRAKEN_AABB_H
#define KRAKEN_AABB_H
#include <functional> // for hash<>
#include "vector2.h"
#include "vector3.h"
namespace kraken {
class Matrix4;
class AABB {
public:
Vector3 min;
Vector3 max;
AABB(const Vector3 &minPoint, const Vector3 &maxPoint);
AABB(const Vector3 &corner1, const Vector3 &corner2, const Matrix4 &modelMatrix);
AABB();
~AABB();
void scale(const Vector3 &s);
void scale(float s);
Vector3 center() const;
Vector3 size() const;
float volume() const;
bool intersects(const AABB& b) const;
bool contains(const AABB &b) const;
bool contains(const Vector3 &v) const;
bool intersectsLine(const Vector3 &v1, const Vector3 &v2) const;
bool intersectsRay(const Vector3 &v1, const Vector3 &dir) const;
bool intersectsSphere(const Vector3 &center, float radius) const;
void encapsulate(const AABB & b);
AABB& operator =(const AABB& b);
bool operator ==(const AABB& b) const;
bool operator !=(const AABB& b) const;
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
bool operator >(const AABB& b) const;
bool operator <(const AABB& b) const;
static AABB Infinite();
static AABB Zero();
float longest_radius() const;
Vector3 nearestPoint(const Vector3 & v) const;
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::AABB> {
public:
size_t operator()(const kraken::AABB &s) const
{
size_t h1 = hash<kraken::Vector3>()(s.min);
size_t h2 = hash<kraken::Vector3>()(s.max);
return h1 ^ ( h2 << 1 );
}
};
} // namespace std
#endif /* defined(KRAKEN_AABB_H) */

View File

@@ -1,65 +0,0 @@
//
// hitinfo.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_HITINFO_H
#define KRAKEN_HITINFO_H
#include "vector3.h"
class KRNode;
namespace kraken {
class HitInfo {
public:
HitInfo();
HitInfo(const Vector3 &position, const Vector3 &normal, const float distance);
HitInfo(const Vector3 &position, const Vector3 &normal, const float distance, KRNode *node);
~HitInfo();
Vector3 getPosition() const;
Vector3 getNormal() const;
float getDistance() const;
KRNode *getNode() const;
bool didHit() const;
HitInfo& operator =(const HitInfo& b);
private:
KRNode *m_node;
Vector3 m_position;
Vector3 m_normal;
float m_distance;
};
} // namespace kraken
#endif

View File

@@ -1,44 +1,35 @@
//
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_H
#define KRAKEN_H
#include "scalar.h"
#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "matrix4.h"
#include "quaternion.h"
#include "aabb.h"
#include "triangle3.h"
#include "hitinfo.h"
#endif // KRAKEN_H
//
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_H
#define KRAKEN_H
#endif // KRAKEN_H

View File

@@ -1,136 +0,0 @@
//
// Matrix4.h
// Kraken
//
// Copyright 2018 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.
//
#include "vector3.h"
#include "vector4.h"
#ifndef KRAKEN_MATRIX4_H
#define KRAKEN_MATRIX4_H
namespace kraken {
typedef enum {
X_AXIS,
Y_AXIS,
Z_AXIS
} AXIS;
class Quaternion;
class Matrix4 {
public:
union {
struct {
Vector4 axis_x, axis_y, axis_z, transform;
};
// Matrix components, in column-major order
float c[16];
};
// Default constructor - Creates an identity matrix
Matrix4();
Matrix4(float *pMat);
Matrix4(const Vector3 &new_axis_x, const Vector3 &new_axis_y, const Vector3 &new_axis_z, const Vector3 &new_transform);
// Destructor
~Matrix4();
// Copy constructor
Matrix4(const Matrix4 &m);
// Overload assignment operator
Matrix4& operator=(const Matrix4 &m);
// Overload comparison operator
bool operator==(const Matrix4 &m) const;
// Overload compound multiply operator
Matrix4& operator*=(const Matrix4 &m);
float& operator[](unsigned i);
float operator[](unsigned i) const;
// Overload multiply operator
//Matrix4& operator*(const Matrix4 &m);
Matrix4 operator*(const Matrix4 &m) const;
float *getPointer();
void perspective(float fov, float aspect, float nearz, float farz);
void ortho(float left, float right, float top, float bottom, float nearz, float farz);
void translate(float x, float y, float z);
void translate(const Vector3 &v);
void scale(float x, float y, float z);
void scale(const Vector3 &v);
void scale(float s);
void rotate(float angle, AXIS axis);
void rotate(const Quaternion &q);
void bias();
bool invert();
void transpose();
static Vector3 DotNoTranslate(const Matrix4 &m, const Vector3 &v); // Dot product without including translation; useful for transforming normals and tangents
static Matrix4 Invert(const Matrix4 &m);
static Matrix4 Transpose(const Matrix4 &m);
static Vector3 Dot(const Matrix4 &m, const Vector3 &v);
static Vector4 Dot4(const Matrix4 &m, const Vector4 &v);
static float DotW(const Matrix4 &m, const Vector3 &v);
static Vector3 DotWDiv(const Matrix4 &m, const Vector3 &v);
static Matrix4 LookAt(const Vector3 &cameraPos, const Vector3 &lookAtPos, const Vector3 &upDirection);
static Matrix4 Translation(const Vector3 &v);
static Matrix4 Rotation(const Vector3 &v);
static Matrix4 Scaling(const Vector3 &v);
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Matrix4> {
public:
size_t operator()(const kraken::Matrix4 &s) const
{
size_t h1 = hash<kraken::Vector4>()(s.axis_x);
size_t h2 = hash<kraken::Vector4>()(s.axis_y);
size_t h3 = hash<kraken::Vector4>()(s.axis_z);
size_t h4 = hash<kraken::Vector4>()(s.transform);
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
}
};
} // namespace std
#endif // KRAKEN_MATRIX4_H

View File

@@ -1,110 +0,0 @@
//
// Quaternion.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_QUATERNION_H
#define KRAKEN_QUATERNION_H
#include "vector3.h"
namespace kraken {
class Quaternion {
public:
union {
struct {
float w, x, y, z;
};
float c[4];
};
Quaternion();
Quaternion(float w, float x, float y, float z);
Quaternion(const Quaternion& p);
Quaternion(const Vector3 &euler);
Quaternion(const Vector3 &from_vector, const Vector3 &to_vector);
~Quaternion();
Quaternion& operator =( const Quaternion& p );
Quaternion operator +(const Quaternion &v) const;
Quaternion operator -(const Quaternion &v) const;
Quaternion operator +() const;
Quaternion operator -() const;
Quaternion operator *(const Quaternion &v);
Quaternion operator *(float num) const;
Quaternion operator /(float num) const;
Quaternion& operator +=(const Quaternion& v);
Quaternion& operator -=(const Quaternion& v);
Quaternion& operator *=(const Quaternion& v);
Quaternion& operator *=(const float& v);
Quaternion& operator /=(const float& v);
friend bool operator ==(Quaternion &v1, Quaternion &v2);
friend bool operator !=(Quaternion &v1, Quaternion &v2);
float& operator [](unsigned i);
float operator [](unsigned i) const;
void setEulerXYZ(const Vector3 &euler);
void setEulerZYX(const Vector3 &euler);
Vector3 eulerXYZ() const;
Matrix4 rotationMatrix() const;
void normalize();
static Quaternion Normalize(const Quaternion &v1);
void conjugate();
static Quaternion Conjugate(const Quaternion &v1);
static Quaternion FromAngleAxis(const Vector3 &axis, float angle);
static Quaternion Lerp(const Quaternion &a, const Quaternion &b, float t);
static Quaternion Slerp(const Quaternion &a, const Quaternion &b, float t);
static float Dot(const Quaternion &v1, const Quaternion &v2);
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Quaternion> {
public:
size_t operator()(const kraken::Quaternion &s) const
{
size_t h1 = hash<float>()(s.c[0]);
size_t h2 = hash<float>()(s.c[1]);
size_t h3 = hash<float>()(s.c[2]);
size_t h4 = hash<float>()(s.c[3]);
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
}
};
} // namespace std
#endif // KRAKEN_QUATERNION_H

View File

@@ -1,41 +0,0 @@
//
// KRFloat.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_SCALAR_H
#define KRAKEN_SCALAR_H
namespace kraken {
float SmoothStep(float a, float b, float t);
}; // namespace kraken
#endif // KRAKEN_SCALAR_H

View File

@@ -1,79 +0,0 @@
//
// KRTriangle.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_TRIANGLE3_H
#define KRAKEN_TRIANGLE3_H
#include "vector3.h"
namespace kraken {
class Triangle3
{
public:
Vector3 vert[3];
Triangle3(const Triangle3 &tri);
Triangle3(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3);
~Triangle3();
Vector3 calculateNormal() const;
bool operator ==(const Triangle3& b) const;
bool operator !=(const Triangle3& b) const;
Triangle3& operator =(const Triangle3& b);
Vector3& operator[](unsigned int i);
Vector3 operator[](unsigned int i) const;
bool rayCast(const Vector3 &start, const Vector3 &dir, Vector3 &hit_point) const;
bool sphereCast(const Vector3 &start, const Vector3 &dir, float radius, Vector3 &hit_point, float &hit_distance) const;
bool containsPoint(const Vector3 &p) const;
Vector3 closestPointOnTriangle(const Vector3 &p) const;
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Triangle3> {
public:
size_t operator()(const kraken::Triangle3 &s) const
{
size_t h1 = hash<kraken::Vector3>()(s.vert[0]);
size_t h2 = hash<kraken::Vector3>()(s.vert[1]);
size_t h3 = hash<kraken::Vector3>()(s.vert[2]);
return h1 ^ (h2 << 1) ^ (h3 << 2);
}
};
} // namespace std
#endif // KRAKEN_TRIANGLE3_H

View File

@@ -1,117 +0,0 @@
//
// vector2.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_VECTOR2_H
#define KRAKEN_VECTOR2_H
#include <functional> // for hash<>
#include <limits> // for std::numeric_limits<>
#include <math.h> // for sqrtf
namespace kraken {
class Vector2 {
public:
union {
struct {
float x, y;
};
float c[2];
};
Vector2();
Vector2(float X, float Y);
Vector2(float v);
Vector2(float *v);
Vector2(const Vector2 &v);
~Vector2();
// Vector2 swizzle getters
Vector2 yx() const;
// Vector2 swizzle setters
void yx(const Vector2 &v);
Vector2& operator =(const Vector2& b);
Vector2 operator +(const Vector2& b) const;
Vector2 operator -(const Vector2& b) const;
Vector2 operator +() const;
Vector2 operator -() const;
Vector2 operator *(const float v) const;
Vector2 operator /(const float v) const;
Vector2& operator +=(const Vector2& b);
Vector2& operator -=(const Vector2& b);
Vector2& operator *=(const float v);
Vector2& operator /=(const float v);
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
bool operator >(const Vector2& b) const;
bool operator <(const Vector2& b) const;
bool operator ==(const Vector2& b) const;
bool operator !=(const Vector2& b) const;
float& operator[](unsigned i);
float operator[](unsigned i) const;
float sqrMagnitude() const;
float magnitude() const;
void normalize();
static Vector2 Normalize(const Vector2 &v);
static float Cross(const Vector2 &v1, const Vector2 &v2);
static float Dot(const Vector2 &v1, const Vector2 &v2);
static Vector2 Min();
static Vector2 Max();
static Vector2 Zero();
static Vector2 One();
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Vector2> {
public:
size_t operator()(const kraken::Vector2 &s) const
{
size_t h1 = hash<float>()(s.x);
size_t h2 = hash<float>()(s.y);
return h1 ^ (h2 << 1);
}
};
} // namespace std
#endif // KRAKEN_VECTOR2_H

View File

@@ -1,146 +0,0 @@
//
// Vector3.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_VECTOR3_H
#define KRAKEN_VECTOR3_H
#include <functional> // for hash<>
#include "vector2.h"
#include "vector4.h"
namespace kraken {
class Vector3 {
public:
union {
struct {
float x, y, z;
};
float c[3];
};
Vector3();
Vector3(float X, float Y, float Z);
Vector3(float v);
Vector3(float *v);
Vector3(double *v);
Vector3(const Vector3 &v);
Vector3(const Vector4 &v);
~Vector3();
// Vector2 swizzle getters
Vector2 xx() const;
Vector2 xy() const;
Vector2 xz() const;
Vector2 yx() const;
Vector2 yy() const;
Vector2 yz() const;
Vector2 zx() const;
Vector2 zy() const;
Vector2 zz() const;
// Vector2 swizzle setters
void xy(const Vector2 &v);
void xz(const Vector2 &v);
void yx(const Vector2 &v);
void yz(const Vector2 &v);
void zx(const Vector2 &v);
void zy(const Vector2 &v);
Vector3& operator =(const Vector3& b);
Vector3& operator =(const Vector4& b);
Vector3 operator +(const Vector3& b) const;
Vector3 operator -(const Vector3& b) const;
Vector3 operator +() const;
Vector3 operator -() const;
Vector3 operator *(const float v) const;
Vector3 operator /(const float v) const;
Vector3& operator +=(const Vector3& b);
Vector3& operator -=(const Vector3& b);
Vector3& operator *=(const float v);
Vector3& operator /=(const float v);
bool operator ==(const Vector3& b) const;
bool operator !=(const Vector3& b) const;
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
bool operator >(const Vector3& b) const;
bool operator <(const Vector3& b) const;
float& operator[](unsigned i);
float operator[](unsigned i) const;
float sqrMagnitude() const; // calculate the square of the magnitude (useful for comparison of magnitudes without the cost of a sqrt() function)
float magnitude() const;
void scale(const Vector3 &v);
void normalize();
static Vector3 Normalize(const Vector3 &v);
static Vector3 Cross(const Vector3 &v1, const Vector3 &v2);
static float Dot(const Vector3 &v1, const Vector3 &v2);
static Vector3 Min();
static Vector3 Max();
static const Vector3 &Zero();
static Vector3 One();
static Vector3 Forward();
static Vector3 Backward();
static Vector3 Up();
static Vector3 Down();
static Vector3 Left();
static Vector3 Right();
static Vector3 Scale(const Vector3 &v1, const Vector3 &v2);
static Vector3 Lerp(const Vector3 &v1, const Vector3 &v2, float d);
static Vector3 Slerp(const Vector3 &v1, const Vector3 &v2, float d);
static void OrthoNormalize(Vector3 &normal, Vector3 &tangent); // Gram-Schmidt Orthonormalization
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Vector3> {
public:
size_t operator()(const kraken::Vector3 &s) const
{
size_t h1 = hash<float>()(s.x);
size_t h2 = hash<float>()(s.y);
size_t h3 = hash<float>()(s.z);
return h1 ^ (h2 << 1) ^ (h3 << 2);
}
};
} // namespace std
#endif // KRAKEN_VECTOR3_H

View File

@@ -1,122 +0,0 @@
//
// Vector4.h
// Kraken
//
// Copyright 2018 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.
//
#ifndef KRAKEN_VECTOR4_H
#define KRAKEN_VECTOR4_H
#include <functional> // for hash<>
namespace kraken {
class Vector3;
class Vector4 {
public:
union {
struct {
float x, y, z, w;
};
float c[4];
};
Vector4();
Vector4(float X, float Y, float Z, float W);
Vector4(float v);
Vector4(float *v);
Vector4(const Vector4 &v);
Vector4(const Vector3 &v, float W);
~Vector4();
Vector4& operator =(const Vector4& b);
Vector4 operator +(const Vector4& b) const;
Vector4 operator -(const Vector4& b) const;
Vector4 operator +() const;
Vector4 operator -() const;
Vector4 operator *(const float v) const;
Vector4 operator /(const float v) const;
Vector4& operator +=(const Vector4& b);
Vector4& operator -=(const Vector4& b);
Vector4& operator *=(const float v);
Vector4& operator /=(const float v);
bool operator ==(const Vector4& b) const;
bool operator !=(const Vector4& b) const;
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
bool operator >(const Vector4& b) const;
bool operator <(const Vector4& b) const;
float& operator[](unsigned i);
float operator[](unsigned i) const;
float sqrMagnitude() const; // calculate the square of the magnitude (useful for comparison of magnitudes without the cost of a sqrt() function)
float magnitude() const;
void normalize();
static Vector4 Normalize(const Vector4 &v);
static float Dot(const Vector4 &v1, const Vector4 &v2);
static Vector4 Min();
static Vector4 Max();
static const Vector4 &Zero();
static Vector4 One();
static Vector4 Forward();
static Vector4 Backward();
static Vector4 Up();
static Vector4 Down();
static Vector4 Left();
static Vector4 Right();
static Vector4 Lerp(const Vector4 &v1, const Vector4 &v2, float d);
static Vector4 Slerp(const Vector4 &v1, const Vector4 &v2, float d);
static void OrthoNormalize(Vector4 &normal, Vector4 &tangent); // Gram-Schmidt Orthonormalization
};
} // namespace kraken
namespace std {
template<>
struct hash<kraken::Vector4> {
public:
size_t operator()(const kraken::Vector4 &s) const
{
size_t h1 = hash<float>()(s.x);
size_t h2 = hash<float>()(s.y);
size_t h3 = hash<float>()(s.z);
size_t h4 = hash<float>()(s.w);
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
}
};
} // namespace std
#endif // KRAKEN_VECTOR4_H

View File

@@ -1,365 +0,0 @@
//
// Quaternion.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.
//
#include "public/kraken.h"
#include "KRHelpers.h"
namespace kraken {
Quaternion::Quaternion() {
c[0] = 1.0;
c[1] = 0.0;
c[2] = 0.0;
c[3] = 0.0;
}
Quaternion::Quaternion(float w, float x, float y, float z) {
c[0] = w;
c[1] = x;
c[2] = y;
c[3] = z;
}
Quaternion::Quaternion(const Quaternion& p) {
c[0] = p[0];
c[1] = p[1];
c[2] = p[2];
c[3] = p[3];
}
Quaternion& Quaternion::operator =( const Quaternion& p ) {
c[0] = p[0];
c[1] = p[1];
c[2] = p[2];
c[3] = p[3];
return *this;
}
Quaternion::Quaternion(const Vector3 &euler) {
setEulerZYX(euler);
}
Quaternion::Quaternion(const Vector3 &from_vector, const Vector3 &to_vector) {
Vector3 a = Vector3::Cross(from_vector, to_vector);
c[0] = a[0];
c[1] = a[1];
c[2] = a[2];
c[3] = sqrt(from_vector.sqrMagnitude() * to_vector.sqrMagnitude()) + Vector3::Dot(from_vector, to_vector);
normalize();
}
Quaternion::~Quaternion() {
}
void Quaternion::setEulerXYZ(const Vector3 &euler)
{
*this = Quaternion::FromAngleAxis(Vector3(1.0f, 0.0f, 0.0f), euler.x)
* Quaternion::FromAngleAxis(Vector3(0.0f, 1.0f, 0.0f), euler.y)
* Quaternion::FromAngleAxis(Vector3(0.0f, 0.0f, 1.0f), euler.z);
}
void Quaternion::setEulerZYX(const Vector3 &euler) {
// ZYX Order!
float c1 = cos(euler[0] * 0.5f);
float c2 = cos(euler[1] * 0.5f);
float c3 = cos(euler[2] * 0.5f);
float s1 = sin(euler[0] * 0.5f);
float s2 = sin(euler[1] * 0.5f);
float s3 = sin(euler[2] * 0.5f);
c[0] = c1 * c2 * c3 + s1 * s2 * s3;
c[1] = s1 * c2 * c3 - c1 * s2 * s3;
c[2] = c1 * s2 * c3 + s1 * c2 * s3;
c[3] = c1 * c2 * s3 - s1 * s2 * c3;
}
float Quaternion::operator [](unsigned i) const {
return c[i];
}
float &Quaternion::operator [](unsigned i) {
return c[i];
}
Vector3 Quaternion::eulerXYZ() const {
double a2 = 2 * (c[0] * c[2] - c[1] * c[3]);
if(a2 <= -0.99999) {
return Vector3(
2.0 * atan2(c[1], c[0]),
-PI * 0.5f,
0
);
} else if(a2 >= 0.99999) {
return Vector3(
2.0 * atan2(c[1], c[0]),
PI * 0.5f,
0
);
} else {
return Vector3(
atan2(2 * (c[0] * c[1] + c[2] * c[3]), (1 - 2 * (c[1] * c[1] + c[2] * c[2]))),
asin(a2),
atan2(2 * (c[0] * c[3] + c[1] * c[2]), (1 - 2 * (c[2] * c[2] + c[3] * c[3])))
);
}
}
bool operator ==(Quaternion &v1, Quaternion &v2) {
return
v1[0] == v2[0]
&& v1[1] == v2[1]
&& v1[2] == v2[2]
&& v1[3] == v2[3];
}
bool operator !=(Quaternion &v1, Quaternion &v2) {
return
v1[0] != v2[0]
|| v1[1] != v2[1]
|| v1[2] != v2[2]
|| v1[3] != v2[3];
}
Quaternion Quaternion::operator *(const Quaternion &v) {
float t0 = (c[3]-c[2])*(v[2]-v[3]);
float t1 = (c[0]+c[1])*(v[0]+v[1]);
float t2 = (c[0]-c[1])*(v[2]+v[3]);
float t3 = (c[3]+c[2])*(v[0]-v[1]);
float t4 = (c[3]-c[1])*(v[1]-v[2]);
float t5 = (c[3]+c[1])*(v[1]+v[2]);
float t6 = (c[0]+c[2])*(v[0]-v[3]);
float t7 = (c[0]-c[2])*(v[0]+v[3]);
float t8 = t5+t6+t7;
float t9 = (t4+t8)/2;
return Quaternion(
t0+t9-t5,
t1+t9-t8,
t2+t9-t7,
t3+t9-t6
);
}
Quaternion Quaternion::operator *(float v) const {
return Quaternion(c[0] * v, c[1] * v, c[2] * v, c[3] * v);
}
Quaternion Quaternion::operator /(float num) const {
float inv_num = 1.0f / num;
return Quaternion(c[0] * inv_num, c[1] * inv_num, c[2] * inv_num, c[3] * inv_num);
}
Quaternion Quaternion::operator +(const Quaternion &v) const {
return Quaternion(c[0] + v[0], c[1] + v[1], c[2] + v[2], c[3] + v[3]);
}
Quaternion Quaternion::operator -(const Quaternion &v) const {
return Quaternion(c[0] - v[0], c[1] - v[1], c[2] - v[2], c[3] - v[3]);
}
Quaternion& Quaternion::operator +=(const Quaternion& v) {
c[0] += v[0];
c[1] += v[1];
c[2] += v[2];
c[3] += v[3];
return *this;
}
Quaternion& Quaternion::operator -=(const Quaternion& v) {
c[0] -= v[0];
c[1] -= v[1];
c[2] -= v[2];
c[3] -= v[3];
return *this;
}
Quaternion& Quaternion::operator *=(const Quaternion& v) {
float t0 = (c[3]-c[2])*(v[2]-v[3]);
float t1 = (c[0]+c[1])*(v[0]+v[1]);
float t2 = (c[0]-c[1])*(v[2]+v[3]);
float t3 = (c[3]+c[2])*(v[0]-v[1]);
float t4 = (c[3]-c[1])*(v[1]-v[2]);
float t5 = (c[3]+c[1])*(v[1]+v[2]);
float t6 = (c[0]+c[2])*(v[0]-v[3]);
float t7 = (c[0]-c[2])*(v[0]+v[3]);
float t8 = t5+t6+t7;
float t9 = (t4+t8)/2;
c[0] = t0+t9-t5;
c[1] = t1+t9-t8;
c[2] = t2+t9-t7;
c[3] = t3+t9-t6;
return *this;
}
Quaternion& Quaternion::operator *=(const float& v) {
c[0] *= v;
c[1] *= v;
c[2] *= v;
c[3] *= v;
return *this;
}
Quaternion& Quaternion::operator /=(const float& v) {
float inv_v = 1.0f / v;
c[0] *= inv_v;
c[1] *= inv_v;
c[2] *= inv_v;
c[3] *= inv_v;
return *this;
}
Quaternion Quaternion::operator +() const {
return *this;
}
Quaternion Quaternion::operator -() const {
return Quaternion(-c[0], -c[1], -c[2], -c[3]);
}
Quaternion Normalize(const Quaternion &v1) {
float inv_magnitude = 1.0f / sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]);
return Quaternion(
v1[0] * inv_magnitude,
v1[1] * inv_magnitude,
v1[2] * inv_magnitude,
v1[3] * inv_magnitude
);
}
void Quaternion::normalize() {
float inv_magnitude = 1.0f / sqrtf(c[0] * c[0] + c[1] * c[1] + c[2] * c[2] + c[3] * c[3]);
c[0] *= inv_magnitude;
c[1] *= inv_magnitude;
c[2] *= inv_magnitude;
c[3] *= inv_magnitude;
}
Quaternion Conjugate(const Quaternion &v1) {
return Quaternion(v1[0], -v1[1], -v1[2], -v1[3]);
}
void Quaternion::conjugate() {
c[1] = -c[1];
c[2] = -c[2];
c[3] = -c[3];
}
Matrix4 Quaternion::rotationMatrix() const {
Matrix4 matRotate;
/*
Vector3 euler = eulerXYZ();
matRotate.rotate(euler.x, X_AXIS);
matRotate.rotate(euler.y, Y_AXIS);
matRotate.rotate(euler.z, Z_AXIS);
*/
// FINDME - Determine why the more optimal routine commented below wasn't working
matRotate.c[0] = 1.0 - 2.0 * (c[2] * c[2] + c[3] * c[3]);
matRotate.c[1] = 2.0 * (c[1] * c[2] - c[0] * c[3]);
matRotate.c[2] = 2.0 * (c[0] * c[2] + c[1] * c[3]);
matRotate.c[4] = 2.0 * (c[1] * c[2] + c[0] * c[3]);
matRotate.c[5] = 1.0 - 2.0 * (c[1] * c[1] + c[3] * c[3]);
matRotate.c[6] = 2.0 * (c[2] * c[3] - c[0] * c[1]);
matRotate.c[8] = 2.0 * (c[1] * c[3] - c[0] * c[2]);
matRotate.c[9] = 2.0 * (c[0] * c[1] + c[2] * c[3]);
matRotate.c[10] = 1.0 - 2.0 * (c[1] * c[1] + c[2] * c[2]);
return matRotate;
}
Quaternion Quaternion::FromAngleAxis(const Vector3 &axis, float angle)
{
float ha = angle * 0.5f;
float sha = sin(ha);
return Quaternion(cos(ha), axis.x * sha, axis.y * sha, axis.z * sha);
}
float Quaternion::Dot(const Quaternion &v1, const Quaternion &v2)
{
return v1.c[0] * v2.c[0] + v1.c[1] * v2.c[1] + v1.c[2] * v2.c[2] + v1.c[3] * v2.c[3];
}
Quaternion Quaternion::Lerp(const Quaternion &a, const Quaternion &b, float t)
{
if (t <= 0.0f) {
return a;
} else if (t >= 1.0f) {
return b;
}
return a * (1.0f - t) + b * t;
}
Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float t)
{
if (t <= 0.0f) {
return a;
}
if (t >= 1.0f) {
return b;
}
float coshalftheta = Dot(a, b);
Quaternion c = a;
// Angle is greater than 180. We can negate the angle/quat to get the
// shorter rotation to reach the same destination.
if ( coshalftheta < 0.0f ) {
coshalftheta = -coshalftheta;
c = -c;
}
if ( coshalftheta > (1.0f - std::numeric_limits<float>::epsilon())) {
// Angle is tiny - save some computation by lerping instead.
return Lerp(c, b, t);
}
float halftheta = acos(coshalftheta);
return (c * sin((1.0f - t) * halftheta) + b * sin(t * halftheta)) / sin(halftheta);
}
} // namespace kraken

View File

@@ -1,19 +0,0 @@
//
// KRFloat.cpp
// Kraken
//
// Created by Kearwood Gilbert on 2013-05-03.
// Copyright (c) 2013 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
namespace kraken {
float SmoothStep(float a, float b, float t)
{
float d = (3.0 * t * t - 2.0 * t * t * t);
return a * (1.0f - d) + b * d;
}
} // namespace kraken

View File

@@ -1,331 +0,0 @@
//
// KRTriangle.cpp
// Kraken
//
// Created by Kearwood Gilbert on 2/8/2014.
// Copyright (c) 2014 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
using namespace kraken;
namespace {
bool _intersectSphere(const Vector3 &start, const Vector3 &dir, const Vector3 &sphere_center, float sphere_radius, float &distance)
{
// dir must be normalized
// From: http://archive.gamedev.net/archive/reference/articles/article1026.html
// TODO - Move to another class?
Vector3 Q = sphere_center - start;
float c = Q.magnitude();
float v = Vector3::Dot(Q, dir);
float d = sphere_radius * sphere_radius - (c * c - v * v);
if (d < 0.0) {
// No intersection
return false;
}
// Return the distance to the [first] intersecting point
distance = v - sqrt(d);
if (distance < 0.0f) {
return false;
}
return true;
}
bool _sameSide(const Vector3 &p1, const Vector3 &p2, const Vector3 &a, const Vector3 &b)
{
// TODO - Move to Vector3 class?
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
Vector3 cp1 = Vector3::Cross(b - a, p1 - a);
Vector3 cp2 = Vector3::Cross(b - a, p2 - a);
if (Vector3::Dot(cp1, cp2) >= 0) return true;
return false;
}
Vector3 _closestPointOnLine(const Vector3 &a, const Vector3 &b, const Vector3 &p)
{
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
// Determine t (the length of the vector from a to p)
Vector3 c = p - a;
Vector3 V = Vector3::Normalize(b - a);
float d = (a - b).magnitude();
float t = Vector3::Dot(V, c);
// Check to see if t is beyond the extents of the line segment
if (t < 0) return a;
if (t > d) return b;
// Return the point between a and b
return a + V * t;
}
} // anonymous namespace
namespace kraken {
Triangle3::Triangle3(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
{
vert[0] = v1;
vert[1] = v2;
vert[2] = v3;
}
Triangle3::Triangle3(const Triangle3 &tri)
{
vert[0] = tri[0];
vert[1] = tri[1];
vert[3] = tri[3];
}
Triangle3::~Triangle3()
{
}
bool Triangle3::operator ==(const Triangle3& b) const
{
return vert[0] == b[0] && vert[1] == b[1] && vert[2] == b[2];
}
bool Triangle3::operator !=(const Triangle3& b) const
{
return vert[0] != b[0] || vert[1] != b[1] || vert[2] != b[2];
}
Triangle3& Triangle3::operator =(const Triangle3& b)
{
vert[0] = b[0];
vert[1] = b[1];
vert[3] = b[3];
return *this;
}
Vector3& Triangle3::operator[](unsigned int i)
{
return vert[i];
}
Vector3 Triangle3::operator[](unsigned int i) const
{
return vert[i];
}
bool Triangle3::rayCast(const Vector3 &start, const Vector3 &dir, Vector3 &hit_point) const
{
// algorithm based on Dan Sunday's implementation at http://geomalgorithms.com/a06-_intersect-2.html
const float SMALL_NUM = 0.00000001; // anything that avoids division overflow
Vector3 u, v, n; // triangle vectors
Vector3 w0, w; // ray vectors
float r, a, b; // params to calc ray-plane intersect
// get triangle edge vectors and plane normal
u = vert[1] - vert[0];
v = vert[2] - vert[0];
n = Vector3::Cross(u, v); // cross product
if (n == Vector3::Zero()) // triangle is degenerate
return false; // do not deal with this case
w0 = start - vert[0];
a = -Vector3::Dot(n, w0);
b = Vector3::Dot(n,dir);
if (fabs(b) < SMALL_NUM) { // ray is parallel to triangle plane
if (a == 0)
return false; // ray lies in triangle plane
else {
return false; // ray disjoint from plane
}
}
// get intersect point of ray with triangle plane
r = a / b;
if (r < 0.0) // ray goes away from triangle
return false; // => no intersect
// for a segment, also test if (r > 1.0) => no intersect
Vector3 plane_hit_point = start + dir * r; // intersect point of ray and plane
// is plane_hit_point inside triangle?
float uu, uv, vv, wu, wv, D;
uu = Vector3::Dot(u,u);
uv = Vector3::Dot(u,v);
vv = Vector3::Dot(v,v);
w = plane_hit_point - vert[0];
wu = Vector3::Dot(w,u);
wv = Vector3::Dot(w,v);
D = uv * uv - uu * vv;
// get and test parametric coords
float s, t;
s = (uv * wv - vv * wu) / D;
if (s < 0.0 || s > 1.0) // plane_hit_point is outside triangle
return false;
t = (uv * wu - uu * wv) / D;
if (t < 0.0 || (s + t) > 1.0) // plane_hit_point is outside triangle
return false;
// plane_hit_point is inside the triangle
hit_point = plane_hit_point;
return true;
}
Vector3 Triangle3::calculateNormal() const
{
Vector3 v1 = vert[1] - vert[0];
Vector3 v2 = vert[2] - vert[0];
return Vector3::Normalize(Vector3::Cross(v1, v2));
}
Vector3 Triangle3::closestPointOnTriangle(const Vector3 &p) const
{
Vector3 a = vert[0];
Vector3 b = vert[1];
Vector3 c = vert[2];
Vector3 Rab = _closestPointOnLine(a, b, p);
Vector3 Rbc = _closestPointOnLine(b, c, p);
Vector3 Rca = _closestPointOnLine(c, a, p);
// return closest [Rab, Rbc, Rca] to p;
float sd_Rab = (p - Rab).sqrMagnitude();
float sd_Rbc = (p - Rbc).sqrMagnitude();
float sd_Rca = (p - Rca).sqrMagnitude();
if(sd_Rab < sd_Rbc && sd_Rab < sd_Rca) {
return Rab;
} else if(sd_Rbc < sd_Rab && sd_Rbc < sd_Rca) {
return Rbc;
} else {
return Rca;
}
}
bool Triangle3::sphereCast(const Vector3 &start, const Vector3 &dir, float radius, Vector3 &hit_point, float &hit_distance) const
{
// Dir must be normalized
const float SMALL_NUM = 0.001f; // anything that avoids division overflow
Vector3 tri_normal = calculateNormal();
float d = Vector3::Dot(tri_normal, vert[0]);
float e = Vector3::Dot(tri_normal, start) - radius;
float cotangent_distance = e - d;
Vector3 plane_intersect;
float plane_intersect_distance;
float denom = Vector3::Dot(tri_normal, dir);
if(denom > -SMALL_NUM) {
return false; // dir is co-planar with the triangle or going in the direction of the normal; no intersection
}
// Detect an embedded plane, caused by a sphere that is already intersecting the plane.
if(cotangent_distance <= 0 && cotangent_distance >= -radius * 2.0f) {
// Embedded plane - Sphere is already intersecting the plane.
// Use the point closest to the origin of the sphere as the intersection
plane_intersect = start - tri_normal * (cotangent_distance + radius);
plane_intersect_distance = 0.0f;
} else {
// Sphere is not intersecting the plane
// Determine the first point hit by the swept sphere on the triangle's plane
plane_intersect_distance = -(cotangent_distance / denom);
plane_intersect = start + dir * plane_intersect_distance - tri_normal * radius;
}
if(plane_intersect_distance < 0.0f) {
return false;
}
if(containsPoint(plane_intersect)) {
// Triangle contains point
hit_point = plane_intersect;
hit_distance = plane_intersect_distance;
return true;
} else {
// Triangle does not contain point, cast ray back to sphere from closest point on triangle edge or vertice
Vector3 closest_point = closestPointOnTriangle(plane_intersect);
float reverse_hit_distance;
if(_intersectSphere(closest_point, -dir, start, radius, reverse_hit_distance)) {
// Reverse cast hit sphere
hit_distance = reverse_hit_distance;
hit_point = closest_point;
return true;
} else {
// Reverse cast did not hit sphere
return false;
}
}
}
bool Triangle3::containsPoint(const Vector3 &p) const
{
/*
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
const float SMALL_NUM = 0.00000001f; // anything that avoids division overflow
// Vector3 A = vert[0], B = vert[1], C = vert[2];
if (_sameSide(p, vert[0], vert[1], vert[2]) && _sameSide(p, vert[1], vert[0], vert[2]) && _sameSide(p, vert[2], vert[0], vert[1])) {
Vector3 vc1 = Vector3::Cross(vert[0] - vert[1], vert[0] - vert[2]);
if(fabs(Vector3::Dot(vert[0] - p, vc1)) <= SMALL_NUM) {
return true;
}
}
return false;
*/
// From: http://blogs.msdn.com/b/rezanour/archive/2011/08/07/barycentric-coordinates-and-point-in-triangle-tests.aspx
Vector3 A = vert[0];
Vector3 B = vert[1];
Vector3 C = vert[2];
Vector3 P = p;
// Prepare our barycentric variables
Vector3 u = B - A;
Vector3 v = C - A;
Vector3 w = P - A;
Vector3 vCrossW = Vector3::Cross(v, w);
Vector3 vCrossU = Vector3::Cross(v, u);
// Test sign of r
if (Vector3::Dot(vCrossW, vCrossU) < 0)
return false;
Vector3 uCrossW = Vector3::Cross(u, w);
Vector3 uCrossV = Vector3::Cross(u, v);
// Test sign of t
if (Vector3::Dot(uCrossW, uCrossV) < 0)
return false;
// At this point, we know that r and t and both > 0.
// Therefore, as long as their sum is <= 1, each must be less <= 1
float denom = uCrossV.magnitude();
float r = vCrossW.magnitude() / denom;
float t = uCrossW.magnitude() / denom;
return (r + t <= 1);
}
} // namespace kraken

View File

@@ -1,215 +0,0 @@
//
// Vector2.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-03-22.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
#include "public/kraken.h"
namespace kraken {
Vector2::Vector2() {
x = 0.0;
y = 0.0;
}
Vector2::Vector2(float X, float Y) {
x = X;
y = Y;
}
Vector2::Vector2(float v) {
x = v;
y = v;
}
Vector2::Vector2(float *v) {
x = v[0];
y = v[1];
}
Vector2::Vector2(const Vector2 &v) {
x = v.x;
y = v.y;
}
// Vector2 swizzle getters
Vector2 Vector2::yx() const
{
return Vector2(y,x);
}
// Vector2 swizzle setters
void Vector2::yx(const Vector2 &v)
{
y = v.x;
x = v.y;
}
Vector2 Vector2::Min() {
return Vector2(-std::numeric_limits<float>::max());
}
Vector2 Vector2::Max() {
return Vector2(std::numeric_limits<float>::max());
}
Vector2 Vector2::Zero() {
return Vector2(0.0f);
}
Vector2 Vector2::One() {
return Vector2(1.0f);
}
Vector2::~Vector2() {
}
Vector2& Vector2::operator =(const Vector2& b) {
x = b.x;
y = b.y;
return *this;
}
Vector2 Vector2::operator +(const Vector2& b) const {
return Vector2(x + b.x, y + b.y);
}
Vector2 Vector2::operator -(const Vector2& b) const {
return Vector2(x - b.x, y - b.y);
}
Vector2 Vector2::operator +() const {
return *this;
}
Vector2 Vector2::operator -() const {
return Vector2(-x, -y);
}
Vector2 Vector2::operator *(const float v) const {
return Vector2(x * v, y * v);
}
Vector2 Vector2::operator /(const float v) const {
float inv_v = 1.0f / v;
return Vector2(x * inv_v, y * inv_v);
}
Vector2& Vector2::operator +=(const Vector2& b) {
x += b.x;
y += b.y;
return *this;
}
Vector2& Vector2::operator -=(const Vector2& b) {
x -= b.x;
y -= b.y;
return *this;
}
Vector2& Vector2::operator *=(const float v) {
x *= v;
y *= v;
return *this;
}
Vector2& Vector2::operator /=(const float v) {
float inv_v = 1.0f / v;
x *= inv_v;
y *= inv_v;
return *this;
}
bool Vector2::operator ==(const Vector2& b) const {
return x == b.x && y == b.y;
}
bool Vector2::operator !=(const Vector2& b) const {
return x != b.x || y != b.y;
}
bool Vector2::operator >(const Vector2& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x > b.x) {
return true;
} else if(x < b.x) {
return false;
} else if(y > b.y) {
return true;
} else {
return false;
}
}
bool Vector2::operator <(const Vector2& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x < b.x) {
return true;
} else if(x > b.x) {
return false;
} else if(y < b.y) {
return true;
} else {
return false;
}
}
float& Vector2::operator[] (unsigned i) {
switch(i) {
case 0:
return x;
case 1:
default:
return y;
}
}
float Vector2::operator[](unsigned i) const {
switch(i) {
case 0:
return x;
case 1:
default:
return y;
}
}
void Vector2::normalize() {
float inv_magnitude = 1.0f / sqrtf(x * x + y * y);
x *= inv_magnitude;
y *= inv_magnitude;
}
float Vector2::sqrMagnitude() const {
return x * x + y * y;
}
float Vector2::magnitude() const {
return sqrtf(x * x + y * y);
}
Vector2 Vector2::Normalize(const Vector2 &v) {
float inv_magnitude = 1.0f / sqrtf(v.x * v.x + v.y * v.y);
return Vector2(v.x * inv_magnitude, v.y * inv_magnitude);
}
float Vector2::Cross(const Vector2 &v1, const Vector2 &v2) {
return v1.x * v2.y - v1.y * v2.x;
}
float Vector2::Dot(const Vector2 &v1, const Vector2 &v2) {
return v1.x * v2.x + v1.y * v2.y;
}
} // namepsace kraken

View File

@@ -1,418 +0,0 @@
//
// Vector3.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.
//
#include "public/kraken.h"
namespace kraken {
const Vector3 Vector3_ZERO(0.0f, 0.0f, 0.0f);
//default constructor
Vector3::Vector3()
{
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
Vector3::Vector3(const Vector3 &v) {
x = v.x;
y = v.y;
z = v.z;
}
Vector3::Vector3(const Vector4 &v) {
x = v.x;
y = v.y;
z = v.z;
}
Vector3::Vector3(float *v) {
x = v[0];
y = v[1];
z = v[2];
}
Vector3::Vector3(double *v) {
x = (float)v[0];
y = (float)v[1];
z = (float)v[2];
}
Vector2 Vector3::xx() const
{
return Vector2(x,x);
}
Vector2 Vector3::xy() const
{
return Vector2(x,y);
}
Vector2 Vector3::xz() const
{
return Vector2(x,z);
}
Vector2 Vector3::yx() const
{
return Vector2(y,x);
}
Vector2 Vector3::yy() const
{
return Vector2(y,y);
}
Vector2 Vector3::yz() const
{
return Vector2(y,z);
}
Vector2 Vector3::zx() const
{
return Vector2(z,x);
}
Vector2 Vector3::zy() const
{
return Vector2(z,y);
}
Vector2 Vector3::zz() const
{
return Vector2(z,z);
}
void Vector3::xy(const Vector2 &v)
{
x = v.x;
y = v.y;
}
void Vector3::xz(const Vector2 &v)
{
x = v.x;
z = v.y;
}
void Vector3::yx(const Vector2 &v)
{
y = v.x;
x = v.y;
}
void Vector3::yz(const Vector2 &v)
{
y = v.x;
z = v.y;
}
void Vector3::zx(const Vector2 &v)
{
z = v.x;
x = v.y;
}
void Vector3::zy(const Vector2 &v)
{
z = v.x;
y = v.y;
}
Vector3 Vector3::Min() {
return Vector3(-std::numeric_limits<float>::max());
}
Vector3 Vector3::Max() {
return Vector3(std::numeric_limits<float>::max());
}
const Vector3 &Vector3::Zero() {
return Vector3_ZERO;
}
Vector3 Vector3::One() {
return Vector3(1.0f, 1.0f, 1.0f);
}
Vector3 Vector3::Forward() {
return Vector3(0.0f, 0.0f, 1.0f);
}
Vector3 Vector3::Backward() {
return Vector3(0.0f, 0.0f, -1.0f);
}
Vector3 Vector3::Up() {
return Vector3(0.0f, 1.0f, 0.0f);
}
Vector3 Vector3::Down() {
return Vector3(0.0f, -1.0f, 0.0f);
}
Vector3 Vector3::Left() {
return Vector3(-1.0f, 0.0f, 0.0f);
}
Vector3 Vector3::Right() {
return Vector3(1.0f, 0.0f, 0.0f);
}
void Vector3::scale(const Vector3 &v)
{
x *= v.x;
y *= v.y;
z *= v.z;
}
Vector3 Vector3::Scale(const Vector3 &v1, const Vector3 &v2)
{
return Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}
Vector3 Vector3::Lerp(const Vector3 &v1, const Vector3 &v2, float d) {
return v1 + (v2 - v1) * d;
}
Vector3 Vector3::Slerp(const Vector3 &v1, const Vector3 &v2, float d) {
// From: http://keithmaggio.wordpress.com/2011/02/15/math-magician-lerp-slerp-and-nlerp/
// Dot product - the cosine of the angle between 2 vectors.
float dot = Vector3::Dot(v1, v2);
// Clamp it to be in the range of Acos()
if(dot < -1.0f) dot = -1.0f;
if(dot > 1.0f) dot = 1.0f;
// Acos(dot) returns the angle between start and end,
// And multiplying that by percent returns the angle between
// start and the final result.
float theta = acos(dot)*d;
Vector3 RelativeVec = v2 - v1*dot;
RelativeVec.normalize(); // Orthonormal basis
// The final result.
return ((v1*cos(theta)) + (RelativeVec*sin(theta)));
}
void Vector3::OrthoNormalize(Vector3 &normal, Vector3 &tangent) {
// Gram-Schmidt Orthonormalization
normal.normalize();
Vector3 proj = normal * Dot(tangent, normal);
tangent = tangent - proj;
tangent.normalize();
}
Vector3::Vector3(float v) {
x = v;
y = v;
z = v;
}
Vector3::Vector3(float X, float Y, float Z)
{
x = X;
y = Y;
z = Z;
}
Vector3::~Vector3()
{
}
Vector3& Vector3::operator =(const Vector3& b) {
x = b.x;
y = b.y;
z = b.z;
return *this;
}
Vector3& Vector3::operator =(const Vector4 &b) {
x = b.x;
y = b.y;
z = b.z;
return *this;
}
Vector3 Vector3::operator +(const Vector3& b) const {
return Vector3(x + b.x, y + b.y, z + b.z);
}
Vector3 Vector3::operator -(const Vector3& b) const {
return Vector3(x - b.x, y - b.y, z - b.z);
}
Vector3 Vector3::operator +() const {
return *this;
}
Vector3 Vector3::operator -() const {
return Vector3(-x, -y, -z);
}
Vector3 Vector3::operator *(const float v) const {
return Vector3(x * v, y * v, z * v);
}
Vector3 Vector3::operator /(const float v) const {
float inv_v = 1.0f / v;
return Vector3(x * inv_v, y * inv_v, z * inv_v);
}
Vector3& Vector3::operator +=(const Vector3& b) {
x += b.x;
y += b.y;
z += b.z;
return *this;
}
Vector3& Vector3::operator -=(const Vector3& b) {
x -= b.x;
y -= b.y;
z -= b.z;
return *this;
}
Vector3& Vector3::operator *=(const float v) {
x *= v;
y *= v;
z *= v;
return *this;
}
Vector3& Vector3::operator /=(const float v) {
float inv_v = 1.0f / v;
x *= inv_v;
y *= inv_v;
z *= inv_v;
return *this;
}
bool Vector3::operator ==(const Vector3& b) const {
return x == b.x && y == b.y && z == b.z;
}
bool Vector3::operator !=(const Vector3& b) const {
return x != b.x || y != b.y || z != b.z;
}
float& Vector3::operator[](unsigned i) {
switch(i) {
case 0:
return x;
case 1:
return y;
default:
case 2:
return z;
}
}
float Vector3::operator[](unsigned i) const {
switch(i) {
case 0:
return x;
case 1:
return y;
case 2:
default:
return z;
}
}
float Vector3::sqrMagnitude() const {
// calculate the square of the magnitude (useful for comparison of magnitudes without the cost of a sqrt() function)
return x * x + y * y + z * z;
}
float Vector3::magnitude() const {
return sqrtf(x * x + y * y + z * z);
}
void Vector3::normalize() {
float inv_magnitude = 1.0f / sqrtf(x * x + y * y + z * z);
x *= inv_magnitude;
y *= inv_magnitude;
z *= inv_magnitude;
}
Vector3 Vector3::Normalize(const Vector3 &v) {
float inv_magnitude = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
return Vector3(v.x * inv_magnitude, v.y * inv_magnitude, v.z * inv_magnitude);
}
Vector3 Vector3::Cross(const Vector3 &v1, const Vector3 &v2) {
return Vector3(v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x);
}
float Vector3::Dot(const Vector3 &v1, const Vector3 &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
bool Vector3::operator >(const Vector3& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x > b.x) {
return true;
} else if(x < b.x) {
return false;
} else if(y > b.y) {
return true;
} else if(y < b.y) {
return false;
} else if(z > b.z) {
return true;
} else {
return false;
}
}
bool Vector3::operator <(const Vector3& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x < b.x) {
return true;
} else if(x > b.x) {
return false;
} else if(y < b.y) {
return true;
} else if(y > b.y) {
return false;
} else if(z < b.z) {
return true;
} else {
return false;
}
}
} // namespace kraken

View File

@@ -1,303 +0,0 @@
//
// Vector4.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.
//
#include "public/kraken.h"
namespace kraken {
const Vector4 Vector4_ZERO(0.0f, 0.0f, 0.0f, 0.0f);
//default constructor
Vector4::Vector4()
{
x = 0.0f;
y = 0.0f;
z = 0.0f;
w = 0.0f;
}
Vector4::Vector4(const Vector4 &v) {
x = v.x;
y = v.y;
z = v.z;
w = v.w;
}
Vector4::Vector4(const Vector3 &v, float W) {
x = v.x;
y = v.y;
z = v.z;
w = W;
}
Vector4::Vector4(float *v) {
x = v[0];
y = v[1];
z = v[2];
w = v[3];
}
Vector4 Vector4::Min() {
return Vector4(-std::numeric_limits<float>::max());
}
Vector4 Vector4::Max() {
return Vector4(std::numeric_limits<float>::max());
}
const Vector4 &Vector4::Zero() {
return Vector4_ZERO;
}
Vector4 Vector4::One() {
return Vector4(1.0f, 1.0f, 1.0f, 1.0f);
}
Vector4 Vector4::Forward() {
return Vector4(0.0f, 0.0f, 1.0f, 1.0f);
}
Vector4 Vector4::Backward() {
return Vector4(0.0f, 0.0f, -1.0f, 1.0f);
}
Vector4 Vector4::Up() {
return Vector4(0.0f, 1.0f, 0.0f, 1.0f);
}
Vector4 Vector4::Down() {
return Vector4(0.0f, -1.0f, 0.0f, 1.0f);
}
Vector4 Vector4::Left() {
return Vector4(-1.0f, 0.0f, 0.0f, 1.0f);
}
Vector4 Vector4::Right() {
return Vector4(1.0f, 0.0f, 0.0f, 1.0f);
}
Vector4 Vector4::Lerp(const Vector4 &v1, const Vector4 &v2, float d) {
return v1 + (v2 - v1) * d;
}
Vector4 Vector4::Slerp(const Vector4 &v1, const Vector4 &v2, float d) {
// From: http://keithmaggio.wordpress.com/2011/02/15/math-magician-lerp-slerp-and-nlerp/
// Dot product - the cosine of the angle between 2 vectors.
float dot = Vector4::Dot(v1, v2);
// Clamp it to be in the range of Acos()
if(dot < -1.0f) dot = -1.0f;
if(dot > 1.0f) dot = 1.0f;
// Acos(dot) returns the angle between start and end,
// And multiplying that by percent returns the angle between
// start and the final result.
float theta = acos(dot)*d;
Vector4 RelativeVec = v2 - v1*dot;
RelativeVec.normalize(); // Orthonormal basis
// The final result.
return ((v1*cos(theta)) + (RelativeVec*sin(theta)));
}
void Vector4::OrthoNormalize(Vector4 &normal, Vector4 &tangent) {
// Gram-Schmidt Orthonormalization
normal.normalize();
Vector4 proj = normal * Dot(tangent, normal);
tangent = tangent - proj;
tangent.normalize();
}
Vector4::Vector4(float v) {
x = v;
y = v;
z = v;
w = v;
}
Vector4::Vector4(float X, float Y, float Z, float W)
{
x = X;
y = Y;
z = Z;
w = W;
}
Vector4::~Vector4()
{
}
Vector4& Vector4::operator =(const Vector4& b) {
x = b.x;
y = b.y;
z = b.z;
w = b.w;
return *this;
}
Vector4 Vector4::operator +(const Vector4& b) const {
return Vector4(x + b.x, y + b.y, z + b.z, w + b.w);
}
Vector4 Vector4::operator -(const Vector4& b) const {
return Vector4(x - b.x, y - b.y, z - b.z, w - b.w);
}
Vector4 Vector4::operator +() const {
return *this;
}
Vector4 Vector4::operator -() const {
return Vector4(-x, -y, -z, -w);
}
Vector4 Vector4::operator *(const float v) const {
return Vector4(x * v, y * v, z * v, w * v);
}
Vector4 Vector4::operator /(const float v) const {
return Vector4(x / v, y / v, z / v, w/ v);
}
Vector4& Vector4::operator +=(const Vector4& b) {
x += b.x;
y += b.y;
z += b.z;
w += b.w;
return *this;
}
Vector4& Vector4::operator -=(const Vector4& b) {
x -= b.x;
y -= b.y;
z -= b.z;
w -= b.w;
return *this;
}
Vector4& Vector4::operator *=(const float v) {
x *= v;
y *= v;
z *= v;
w *= v;
return *this;
}
Vector4& Vector4::operator /=(const float v) {
float inv_v = 1.0f / v;
x *= inv_v;
y *= inv_v;
z *= inv_v;
w *= inv_v;
return *this;
}
bool Vector4::operator ==(const Vector4& b) const {
return x == b.x && y == b.y && z == b.z && w == b.w;
}
bool Vector4::operator !=(const Vector4& b) const {
return x != b.x || y != b.y || z != b.z || w != b.w;
}
float& Vector4::operator[](unsigned i) {
switch(i) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
case 3:
return w;
}
}
float Vector4::operator[](unsigned i) const {
switch(i) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
case 3:
return w;
}
}
float Vector4::sqrMagnitude() const {
// calculate the square of the magnitude (useful for comparison of magnitudes without the cost of a sqrt() function)
return x * x + y * y + z * z + w * w;
}
float Vector4::magnitude() const {
return sqrtf(x * x + y * y + z * z + w * w);
}
void Vector4::normalize() {
float inv_magnitude = 1.0f / sqrtf(x * x + y * y + z * z + w * w);
x *= inv_magnitude;
y *= inv_magnitude;
z *= inv_magnitude;
w *= inv_magnitude;
}
Vector4 Vector4::Normalize(const Vector4 &v) {
float inv_magnitude = 1.0f / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
return Vector4(v.x * inv_magnitude, v.y * inv_magnitude, v.z * inv_magnitude, v.w * inv_magnitude);
}
float Vector4::Dot(const Vector4 &v1, const Vector4 &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
}
bool Vector4::operator >(const Vector4& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x != b.x) return x > b.x;
if(y != b.y) return y > b.y;
if(z != b.z) return z > b.z;
if(w != b.w) return w > b.w;
return false;
}
bool Vector4::operator <(const Vector4& b) const
{
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
if(x != b.x) return x < b.x;
if(y != b.y) return y < b.y;
if(z != b.z) return z < b.z;
if(w != b.w) return w < b.w;
return false;
}
} // namespace kraken