librw/src/world.cpp

196 lines
4.1 KiB
C++
Raw Normal View History

#include <cstdio>
#include <cstdlib>
#include <cstring>
2020-04-18 20:30:22 +02:00
#include <cassert>
#include "rwbase.h"
#include "rwerror.h"
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwengine.h"
2017-08-24 15:10:34 +02:00
#define PLUGIN_ID ID_WORLD
namespace rw {
int32 World::numAllocated = 0;
PluginList World::s_plglist = { sizeof(World), sizeof(World), nil, nil };
World*
World::create(void)
{
2017-08-24 15:10:34 +02:00
World *world = (World*)rwMalloc(s_plglist.size, MEMDUR_EVENT | ID_WORLD);
if(world == nil){
2017-07-12 10:10:57 +02:00
RWERROR((ERR_ALLOC, s_plglist.size));
return nil;
}
numAllocated++;
world->object.init(World::ID, 0);
2020-04-19 13:00:35 +02:00
world->localLights.init();
world->globalLights.init();
2020-04-18 20:30:22 +02:00
world->clumps.init();
s_plglist.construct(world);
return world;
}
void
World::destroy(void)
{
s_plglist.destruct(this);
rwFree(this);
numAllocated--;
}
void
World::addLight(Light *light)
{
2020-04-19 13:00:35 +02:00
assert(light->world == nil);
light->world = this;
if(light->getType() < Light::POINT){
2020-04-19 13:00:35 +02:00
this->globalLights.append(&light->inWorld);
2017-08-12 10:25:25 +02:00
}else{
2020-04-19 13:00:35 +02:00
this->localLights.append(&light->inWorld);
2017-08-12 10:25:25 +02:00
if(light->getFrame())
light->getFrame()->updateObjects();
}
}
void
World::removeLight(Light *light)
{
2020-04-19 13:00:35 +02:00
assert(light->world == this);
light->inWorld.remove();
light->world = nil;
}
void
World::addCamera(Camera *cam)
{
2020-04-18 20:30:22 +02:00
assert(cam->world == nil);
cam->world = this;
2017-08-12 10:25:25 +02:00
if(cam->getFrame())
cam->getFrame()->updateObjects();
}
void
World::removeCamera(Camera *cam)
{
2020-04-19 13:00:35 +02:00
assert(cam->world == this);
cam->world = nil;
}
2020-04-18 20:30:22 +02:00
void
World::addAtomic(Atomic *atomic)
{
assert(atomic->world == nil);
atomic->world = this;
if(atomic->getFrame())
atomic->getFrame()->updateObjects();
}
void
World::removeAtomic(Atomic *atomic)
{
assert(atomic->world == this);
atomic->world = nil;
}
void
World::addClump(Clump *clump)
{
assert(clump->world == nil);
clump->world = this;
this->clumps.add(&clump->inWorld);
FORLIST(lnk, clump->atomics)
this->addAtomic(Atomic::fromClump(lnk));
FORLIST(lnk, clump->lights)
this->addLight(Light::fromClump(lnk));
FORLIST(lnk, clump->cameras)
this->addCamera(Camera::fromClump(lnk));
if(clump->getFrame()){
clump->getFrame()->matrix.optimize();
clump->getFrame()->updateObjects();
}
}
void
World::removeClump(Clump *clump)
{
assert(clump->world == this);
clump->inWorld.remove();
FORLIST(lnk, clump->atomics)
this->removeAtomic(Atomic::fromClump(lnk));
FORLIST(lnk, clump->lights)
this->removeLight(Light::fromClump(lnk));
FORLIST(lnk, clump->cameras)
this->removeCamera(Camera::fromClump(lnk));
clump->world = nil;
}
void
World::render(void)
{
// this is very wrong, we really want world sectors
FORLIST(lnk, this->clumps)
Clump::fromWorld(lnk)->render();
}
2020-04-19 13:00:35 +02:00
// Find lights that illuminate an atomic
void
World::enumerateLights(Atomic *atomic, WorldLights *lightData)
{
int32 maxDirectionals, maxLocals;
assert(atomic->world == this);
maxDirectionals = lightData->numDirectionals;
maxLocals = lightData->numLocals;
lightData->numDirectionals = 0;
lightData->numLocals = 0;
lightData->ambient.red = 0.0f;
lightData->ambient.green = 0.0f;
lightData->ambient.blue = 0.0f;
lightData->ambient.alpha = 1.0f;
bool32 normals = atomic->geometry->flags & Geometry::NORMALS;
FORLIST(lnk, this->globalLights){
Light *l = Light::fromWorld(lnk);
if((l->getFlags() & Light::LIGHTATOMICS) == 0)
continue;
if(l->getType() == Light::AMBIENT){
lightData->ambient.red += l->color.red;
lightData->ambient.green += l->color.green;
lightData->ambient.blue += l->color.blue;
}else if(normals && l->getType() == Light::DIRECTIONAL){
if(lightData->numDirectionals < maxDirectionals)
lightData->directionals[lightData->numDirectionals++] = l;
}
}
if(!normals)
return;
// TODO: for this we would use an atomic's world sectors, but we don't have those yet
FORLIST(lnk, this->localLights){
if(lightData->numLocals >= maxLocals)
return;
Light *l = Light::fromWorld(lnk);
if((l->getFlags() & Light::LIGHTATOMICS) == 0)
continue;
// check if spheres are intersecting
Sphere *atomsphere = atomic->getWorldBoundingSphere();
V3d dist = sub(l->getFrame()->getLTM()->pos, atomsphere->center);
if(length(dist) < atomsphere->radius + l->radius)
lightData->locals[lightData->numLocals++] = l;
}
}
}