bullet3d support, Humanoid controlling

This commit is contained in:
floralrainfall 2023-07-20 01:13:25 -04:00
parent ed414707c1
commit 461866a1a4
22 changed files with 186 additions and 24 deletions

View File

@ -34,6 +34,7 @@ jobs:
mingw-w64-${{ matrix.env }}-pugixml
mingw-w64-${{ matrix.env }}-ogre3d
mingw-w64-${{ matrix.env }}-qt6
mingw-w64-${{ matrix.env }}-bullet
- name: Generate Ninja build files
run: cmake -G Ninja -B build -DCI=ON -DCMAKE_BUILD_TYPE=${{ matrix.configuration == 'Release' && 'MinSizeRel' || matrix.configuration }} .

View File

@ -16,6 +16,8 @@ add_compile_options(-Wno-attributes -Wno-return-type) # Ignore warnings generate
find_package(Boost REQUIRED)
find_package(OGRE REQUIRED COMPONENTS Bites CONFIG)
find_package(pugixml REQUIRED)
find_package(Bullet CONFIG REQUIRED)
set(RNR_BULLET_LIBRARIES LinearMath Bullet3Common BulletDynamics BulletSoftBody BulletCollision BulletInverseDynamics)
add_subdirectory(Projects)

2
Dependencies/Luau vendored

@ -1 +1 @@
Subproject commit 218159140c7d79ae745e646da721d12331f536f5
Subproject commit e25de95445f2d635a125ab463426bb7fda017093

View File

@ -76,7 +76,7 @@ namespace RNR
if (!std::filesystem::is_directory("ShaderCache") || !std::filesystem::exists("ShaderCache")) {
std::filesystem::create_directory("ShaderCache");
}
ogreShaderGen->setShaderCachePath("ShaderCache/");
ogreShaderGen->addSceneManager(ogreSceneManager);
@ -220,7 +220,11 @@ namespace RNR
void OgreWidget::closeEvent(QCloseEvent* event)
{
delete world;
ogreWindow->destroy();
ogreRoot->destroySceneManager(ogreSceneManager);
ogreRoot->shutdown();
}
QPaintEngine* OgreWidget::paintEngine() const

View File

@ -138,6 +138,8 @@ void MainWindow::playSolo()
RNR::Players* players = (RNR::Players*)this->ogreWidget->world->getDatamodel()->getService("Players");
RNR::Player* player = players->createLocalPlayer(0);
if(!player)
return;
player->setName(QInputDialog::getText(this, "Player Name", "Enter your player name").toLocal8Bit().data());
player->loadCharacter();

View File

@ -67,5 +67,7 @@ add_library(Engine STATIC
Source/Rendering/Adorn.cpp
)
target_include_directories(Engine PUBLIC ${Boost_INCLUDE_DIRS} Header/)
target_link_libraries(Engine PUBLIC ${Boost_LIBRARIES} pugixml OgreBites Luau.Analysis Luau.Ast Luau.Compiler Luau.VM)
target_include_directories(Engine PUBLIC ${Boost_INCLUDE_DIRS} ${BULLET_ROOT_DIR}/${BULLET_INCLUDE_DIR} Header/)
target_compile_definitions(Engine PUBLIC ${BULLET_DEFINITIONS})
target_link_directories(Engine PUBLIC ${Bullet_DIR}/${BULLET_ROOT_DIR}/${BULLET_LIBRARY_DIRS})
target_link_libraries(Engine PUBLIC ${Boost_LIBRARIES} ${RNR_BULLET_LIBRARIES} pugixml OgreBites Luau.Analysis Luau.Ast Luau.Compiler Luau.VM)

View File

@ -20,6 +20,7 @@ namespace RNR
PartInstance* getTorso();
PartInstance* getHead();
void inputFrame(float dx, float dy);
void createHealthBar();
float getHealth() { return m_health; };

View File

@ -15,6 +15,8 @@ namespace RNR
{
World* m_world;
std::vector<int> scancodes_down;
float m_mouseDX;
float m_mouseDY;
protected:
MouseState state;
public:

View File

@ -13,6 +13,7 @@ namespace RNR
private:
CoordinateFrame m_cframe;
CoordinateFrame m_focus;
Ogre::Radian m_yaw;
virtual void deserializeProperty(char* prop_name, pugi::xml_node prop);
virtual void addProperties(std::vector<ReflectionProperty>& properties);
public:
@ -24,6 +25,7 @@ namespace RNR
virtual std::string getClassName() { return "Camera"; }
CoordinateFrame& getCFrame() { return m_cframe; };
CoordinateFrame& getFocus() { return m_focus; }
Ogre::Radian getYaw() { return m_yaw; }
void setCFrame(CoordinateFrame cframe) { m_cframe = cframe; };
void setFocus(CoordinateFrame focus) { m_focus = focus; }
bool zoom(float distance);

View File

@ -37,7 +37,7 @@ namespace RNR
public:
Instance();
~Instance();
virtual ~Instance();
virtual std::vector<ReflectionProperty> getProperties();
void deserializeXmlProperty(pugi::xml_node prop); // TODO: eventually replace this with a method that uses getProperties

View File

@ -15,6 +15,7 @@ namespace RNR
CoordinateFrame& getCFrame() { return m_cframe; };
void setCFrame(CoordinateFrame cframe) { m_cframe = cframe; };
Ogre::Vector3 relativePositionTo(PVInstance* point);
virtual std::string getClassName() { return "PVInstance"; }
Ogre::Vector3 getPosition() { return m_cframe.getPosition(); }

View File

@ -11,6 +11,9 @@
#include <OGRE/Ogre.h>
#include <pugixml.hpp>
#include <stack>
#include "LinearMath/btVector3.h"
#include "btBulletDynamicsCommon.h"
namespace RNR
{
@ -28,6 +31,7 @@ namespace RNR
private:
std::map<std::string, Instance*> m_refs;
std::stack<WorldUndeserialized> m_undeserialized;
btDiscreteDynamicsWorld* m_dynamicsWorld;
DataModel* m_datamodel;
Workspace* m_workspace;
RunService* m_runService;
@ -52,6 +56,7 @@ namespace RNR
double step(float timestep);
void update();
btDiscreteDynamicsWorld* getDynamicsWorld() { return m_dynamicsWorld; }
float getLastDelta() { return m_lastDelta; }
DataModel* getDatamodel() { return m_datamodel; }
void setInputManager(IInputManager* inputManager) { m_inputManager = inputManager; }

View File

@ -115,6 +115,7 @@ namespace RNR
void TopMenuBar::frame()
{
Workspace* workspace = m_world->getWorkspace();
btDiscreteDynamicsWorld* dynamicsWorld = m_world->getDynamicsWorld();
char debugtext[512];
char render_debugtext[255];
@ -127,7 +128,11 @@ namespace RNR
snprintf(render_debugtext, 255, "using BATCH_STATIC_GEOMETRY\nGeom Regions: %i", workspace->m_geom->getRegions().size());
break;
}
snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n",m_world->getLastDelta(),render_debugtext,m_world->getOgreSceneManager());
snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n\nPhysics\n%i objects, %i constraints",
m_world->getLastDelta(),
render_debugtext,
m_world->getOgreSceneManager(),
dynamicsWorld->getNumCollisionObjects(), dynamicsWorld->getNumConstraints());
m_debugText->setCaption(debugtext);
Players* players = (Players*)m_world->getDatamodel()->getService("Players");

View File

@ -1,5 +1,6 @@
#include <App/Humanoid/Humanoid.hpp>
#include <App/V8/World/World.hpp>
#include <App/InputManager.hpp>
namespace RNR
{
@ -45,13 +46,38 @@ namespace RNR
}
if(getNode())
world->getOgreSceneManager()->destroySceneNode(getNode());
setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode());
Ogre::BillboardSet* healthBarSet = world->getOgreSceneManager()->createBillboardSet("HumanoidHealth" + getParent()->getName());
Ogre::Billboard* healthBarBillboard = healthBarSet->createBillboard(Ogre::Vector3(100, 0, 200));
getNode()->attachObject(healthBarSet);
getNode()->setPosition(getHead()->getPosition());
healthBarSet->setBillboardType(Ogre::BillboardType::BBT_PERPENDICULAR_COMMON);
healthBarSet->setDebugDisplayEnabled(true);
//Ogre::Billboard* healthBarBillboard = healthBarSet->createBillboard(Ogre::Vector3(0, 2, 0), Ogre::ColourValue(1, 0, 0, 1));
Ogre::Billboard* healthBarBillboardFilled = healthBarSet->createBillboard(Ogre::Vector3(0, 2, 0), Ogre::ColourValue(0, 1, 0, 1));
float healthBarScale = 0.5f;
//healthBarBillboard->setDimensions(5 * healthBarScale, 1 * healthBarScale);
healthBarBillboardFilled->setDimensions((m_health / m_maxHealth) * 5.f * healthBarScale, 1 * healthBarScale);
healthBarSet->setCastShadows(true);
printf("Humanoid::createHealthBar: WIP");
Ogre::BillboardSet* nameBarSet = world->getOgreSceneManager()->createBillboardSet("HumanoidName" + getParent()->getName());
nameBarSet->setDebugDisplayEnabled(true);
Ogre::FontPtr comic = Ogre::FontManager::getSingletonPtr()->getByName("ComicSans");
if(!comic)
printf("Humanoid::createHealthBar: comic == NULL\n");
comic->putText(nameBarSet, getParent()->getName(), 1);
int num_billboards = nameBarSet->getNumBillboards();
for(int i = 0; i < num_billboards; i++)
{
Ogre::Billboard* chara = nameBarSet->getBillboard(i);
Ogre::Vector3 chara_pos = chara->getPosition();
chara_pos.y += 2 + healthBarScale;
chara->setPosition(chara_pos);
}
getNode()->attachObject(healthBarSet);
getNode()->attachObject(nameBarSet);
getNode()->setPosition(getHead()->getPosition());
getNode()->setOrientation(getHead()->getRotation());
printf("Humanoid::createHealthBar: WIP\n");
}
void Humanoid::deserializeProperty(char* prop_name, pugi::xml_node prop)
@ -66,6 +92,58 @@ namespace RNR
}
}
void Humanoid::inputFrame(float dx, float dy)
{
IInputManager* inputManager = world->getInputManager();
PartInstance* torso = getTorso();
Camera* camera = world->getWorkspace()->getCurrentCamera();
if(!torso)
{
printf("Humanoid::inputFrame: no torso\n");
return;
}
if(inputManager)
{
Ogre::Matrix3 camera_rotation;
camera_rotation.FromEulerAnglesYXZ(camera->getYaw(), Ogre::Radian(0), Ogre::Radian(0)); // we only want yaw because otherwise the movement target will go through the ground/in the air
Ogre::Quaternion direction = torso->getRotation();
Ogre::Quaternion new_direction = Ogre::Quaternion::nlerp(0.5f, direction, camera_rotation);
float forward = 0;
if(inputManager->isKeyDown('W'))
forward = 16;
Ogre::Vector3 move = Ogre::Vector3(0, 0, -forward);
move = direction * move;
move *= world->getLastDelta();
bool move_valid = true;
// TODO: collision checking
if(!move_valid)
return;
for(auto& child : *getParent()->getChildren())
{
PartInstance* bp = dynamic_cast<PartInstance*>(child);
if(bp)
{
Ogre::Vector3 bp_p = bp->getPosition();
bp_p += move;
bp->getCFrame().setPosition(bp_p);
Ogre::Matrix3 new_rotation_matrix;
new_direction.ToRotationMatrix(new_rotation_matrix);
bp->getCFrame().setRotation(new_rotation_matrix);
bp->updateMatrix();
world->getWorkspace()->setDirty();
}
}
camera->getCFrame().setPosition(camera->getCFrame().getPosition() + move);
}
}
void Humanoid::addProperties(std::vector<ReflectionProperty>& properties)
{
ReflectionProperty _properties[] = {

View File

@ -1,5 +1,6 @@
#include <App/InputManager.hpp>
#include <App/V8/DataModel/Camera.hpp>
#include <App/Humanoid/Humanoid.hpp>
#include <stdio.h>
namespace RNR
@ -9,8 +10,7 @@ namespace RNR
state.mouse_primary = false;
state.mouse_secondary = false;
state.mouse_middle = false;
state.mouse_scroll = 0;
}
state.mouse_scroll = 0; }
void IInputManager::keyDown(int scancode)
{
@ -43,14 +43,14 @@ namespace RNR
{
if(m_world)
{
float xd = x * m_world->getLastDelta();
float yd = y * m_world->getLastDelta();
m_mouseDX = x * m_world->getLastDelta();
m_mouseDY = y * m_world->getLastDelta();
Workspace* workspace = m_world->getWorkspace();
Camera* camera = workspace->getCurrentCamera();
if(camera && state.mouse_secondary)
{
camera->cameraFrame(xd, yd);
camera->cameraFrame(m_mouseDX, m_mouseDY);
resetMouse();
}
@ -59,10 +59,29 @@ namespace RNR
void IInputManager::frame()
{
Workspace* workspace = m_world->getWorkspace();
Camera* camera = workspace->getCurrentCamera();
if(camera)
camera->cameraFrame(0, 0, false); // update camera position
Players* players = (Players*)m_world->getDatamodel()->getService("Players");
Player* localPlayer = players->getLocalPlayer();
if(localPlayer)
{
ModelInstance* character = localPlayer->getCharacter();
if(character)
{
Humanoid* humanoid = (Humanoid*)character->findFirstChildOfType("Humanoid");
if(humanoid)
{
humanoid->inputFrame(m_mouseDX, m_mouseDY);
}
}
}
else
{
Workspace* workspace = m_world->getWorkspace();
Camera* camera = workspace->getCurrentCamera();
if(camera)
camera->cameraFrame(0, 0, false); // update camera position
}
m_mouseDX = 0;
m_mouseDY = 0;
}
void IInputManager::mousePrimaryState(bool down)

View File

@ -41,6 +41,7 @@ namespace RNR
pitch = old_pitch + pitch;
yaw = old_yaw - yaw;
m_yaw = yaw;
Ogre::Matrix3 rotation;
rotation.FromEulerAnglesYXZ(yaw, pitch, Ogre::Radian(0));

View File

@ -8,7 +8,7 @@ namespace RNR
Workspace::Workspace() : ModelInstance()
{
setName("Workspace");
m_batchMode = BATCH_STATIC_GEOMETRY;
m_batchMode = BATCH_DONT;
m_worldspawn = world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode();

View File

@ -15,6 +15,17 @@ namespace RNR
Instance::~Instance()
{
setParent(NULL);
if(getNode())
{
getNode()->removeAndDestroyAllChildren();
delete getNode();
}
if(getObject())
{
if(getObject()->getParentNode() != 0)
getObject()->detachFromParent();
delete getObject();
}
}
std::vector<ReflectionProperty> Instance::getProperties()

View File

@ -6,7 +6,7 @@ namespace RNR
{
PVInstance::PVInstance() : m_cframe(), Instance()
{
}
void PVInstance::deserializeProperty(char* prop_name, pugi::xml_node node)
@ -28,4 +28,9 @@ namespace RNR
properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty)));
}
Ogre::Vector3 PVInstance::relativePositionTo(PVInstance* point)
{
return point->getPosition() - getPosition();
}
}

View File

@ -15,6 +15,13 @@ namespace RNR
{
Instance::setWorld(this);
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
m_dynamicsWorld->setGravity(btVector3(0, -10, 0));
m_inputManager = 0;
m_instanceFactory = new InstanceFactory();
@ -112,7 +119,7 @@ namespace RNR
m_undeserialized.pop();
s.instance->setParent(s.parent);
pugi::xml_node props = s.node.child("Properties");
for(pugi::xml_node prop : props.children())
{
@ -143,7 +150,10 @@ namespace RNR
double World::step(float timestep)
{
if(m_runService && m_runService->getRunning())
{
m_runService->step(timestep);
m_dynamicsWorld->stepSimulation(timestep);
}
m_lastDelta = timestep;
return 0.0;
}

View File

@ -37,8 +37,19 @@ namespace RNR
PartInstance* head = new PartInstance();
head->setName("Head");
head->setSize(Ogre::Vector3(2, 1, 1));
head->setBrickColor(24);
head->getCFrame().setPosition(Ogre::Vector3(0, 1.5, 0));
head->updateMatrix();
head->setParent(m_character);
PartInstance* torso = new PartInstance();
torso->setName("Torso");
torso->setSize(Ogre::Vector3(2, 2, 1));
torso->setBrickColor(23);
torso->getCFrame().setPosition(Ogre::Vector3(0, 0, 0));
torso->updateMatrix();
torso->setParent(m_character);
Humanoid* character_humanoid = new Humanoid();
character_humanoid->setParent(m_character);
m_character->setParent(world->getWorkspace());

View File

@ -12,8 +12,8 @@ namespace RNR
{
if(m_localPlayer)
{
printf("Players::createLocalPlayer: attempt to create another local player\n", userId);
return m_localPlayer;
printf("Players::createLocalPlayer: attempt to create another local player %i\n", userId);
return 0;
}
printf("Players::createLocalPlayer: created player %i\n", userId);
m_localPlayer = new Player();