3068 lines
64 KiB
C++
3068 lines
64 KiB
C++
#include "bbblitz3d.hpp"
|
|
#include <set>
|
|
#include "../blitz3d/animator.hpp"
|
|
#include "../blitz3d/brush.hpp"
|
|
#include "../blitz3d/cachedtexture.hpp"
|
|
#include "../blitz3d/camera.hpp"
|
|
#include "../blitz3d/listener.hpp"
|
|
#include "../blitz3d/loader_3ds.hpp"
|
|
#include "../blitz3d/loader_b3d.hpp"
|
|
#include "../blitz3d/md2model.hpp"
|
|
#include "../blitz3d/meshmodel.hpp"
|
|
#include "../blitz3d/meshutil.hpp"
|
|
#include "../blitz3d/pivot.hpp"
|
|
#include "../blitz3d/planemodel.hpp"
|
|
#include "../blitz3d/q3bspmodel.hpp"
|
|
#include "../blitz3d/sprite.hpp"
|
|
#include "../blitz3d/terrain.hpp"
|
|
#include "../blitz3d/texture.hpp"
|
|
#include "../blitz3d/world.hpp"
|
|
#include "bbgraphics.hpp"
|
|
|
|
#include <stdutil.hpp>
|
|
|
|
gxScene* gx_scene;
|
|
extern gxFileSystem* gx_filesys;
|
|
|
|
static int tri_count;
|
|
static World* world;
|
|
|
|
static std::set<Brush*> brush_set;
|
|
static std::set<Texture*> texture_set;
|
|
static std::set<Entity*> entity_set;
|
|
|
|
static Listener* listener;
|
|
|
|
static bool stats_mode;
|
|
|
|
//converts 0...255 color to 0...1
|
|
static const float s_colorToFloat = 1.0f / 255.0f;
|
|
|
|
//degrees to radians and back
|
|
static const float s_degreesToRadians = 0.0174532925199432957692369076848861f;
|
|
static const float s_radiansToDegrees = 1 / s_degreesToRadians;
|
|
|
|
static Vector projected, tformed;
|
|
|
|
static ObjCollision picked;
|
|
|
|
extern float stats3d[10];
|
|
|
|
//static Loader_X loader_x;
|
|
static Loader_3DS loader_3ds;
|
|
static Loader_B3D loader_b3d;
|
|
|
|
static std::map<std::string, Transform> loader_mat_map;
|
|
|
|
#ifdef _DEBUG
|
|
static inline void debug3d()
|
|
{
|
|
if (debug && !gx_scene)
|
|
ThrowRuntimeException("3D Graphics mode not set");
|
|
}
|
|
static inline void debugTexture(Texture* t)
|
|
{
|
|
if (debug && !texture_set.count(t))
|
|
ThrowRuntimeException("Texture does not exist");
|
|
}
|
|
static inline void debugBrush(Brush* b)
|
|
{
|
|
if (debug && !brush_set.count(b))
|
|
ThrowRuntimeException("Brush does not exist");
|
|
}
|
|
static inline void debugEntity(Entity* e)
|
|
{
|
|
if (debug && !entity_set.count(e))
|
|
ThrowRuntimeException("Entity does not exist");
|
|
}
|
|
static inline void debugParent(Entity* e)
|
|
{
|
|
if (debug) {
|
|
debug3d();
|
|
if (e && !entity_set.count(e))
|
|
ThrowRuntimeException("Parent entity does not exist");
|
|
}
|
|
}
|
|
static inline void debugMesh(MeshModel* m)
|
|
{
|
|
if (debug) {
|
|
debugEntity(m);
|
|
if (!m->getMeshModel())
|
|
ThrowRuntimeException("Entity is not a mesh");
|
|
}
|
|
}
|
|
static inline void debugObject(Object* o)
|
|
{
|
|
if (debug) {
|
|
debugEntity(o);
|
|
if (!o->getObject())
|
|
ThrowRuntimeException("Entity is not an object");
|
|
}
|
|
}
|
|
static inline void debugColl(Object* o, int index)
|
|
{
|
|
if (debug) {
|
|
debugObject(o);
|
|
if (index < 1 || index > o->getCollisions().size())
|
|
ThrowRuntimeException("Collision index out of range");
|
|
}
|
|
}
|
|
static inline void debugCamera(Camera* c)
|
|
{
|
|
if (debug) {
|
|
debugEntity(c);
|
|
if (!c->getCamera())
|
|
ThrowRuntimeException("Entity is not a camera");
|
|
}
|
|
}
|
|
static inline void debugLight(Light* l)
|
|
{
|
|
if (debug) {
|
|
debugEntity(l);
|
|
if (!l->getLight())
|
|
ThrowRuntimeException("Entity is not a light");
|
|
}
|
|
}
|
|
static inline void debugModel(Model* m)
|
|
{
|
|
if (debug) {
|
|
debugEntity(m);
|
|
if (!m->getModel())
|
|
ThrowRuntimeException("Entity is not a model");
|
|
}
|
|
}
|
|
static inline void debugSprite(Sprite* s)
|
|
{
|
|
if (debug) {
|
|
debugModel(s);
|
|
if (!s->getSprite())
|
|
ThrowRuntimeException("Entity is not a sprite");
|
|
}
|
|
}
|
|
static inline void debugMD2(MD2Model* m)
|
|
{
|
|
if (debug) {
|
|
debugModel(m);
|
|
if (!m->getMD2Model())
|
|
ThrowRuntimeException("Entity is not an MD2 Model");
|
|
}
|
|
}
|
|
static inline void debugBSP(Q3BSPModel* m)
|
|
{
|
|
if (debug) {
|
|
debugModel(m);
|
|
if (!m->getBSPModel())
|
|
ThrowRuntimeException("Entity is not a BSP Model");
|
|
}
|
|
}
|
|
static inline void debugTerrain(Terrain* t)
|
|
{
|
|
if (debug) {
|
|
debugModel(t);
|
|
if (!t->getTerrain())
|
|
ThrowRuntimeException("Entity is not a terrain");
|
|
}
|
|
}
|
|
static inline void debugSegs(int n)
|
|
{
|
|
if (debug) {
|
|
debug3d();
|
|
if (n < 3 || n > 50)
|
|
ThrowRuntimeException("Illegal number of segments");
|
|
}
|
|
}
|
|
static inline void debugVertex(Surface* s, int n)
|
|
{
|
|
if (debug) {
|
|
debug3d();
|
|
if (n < 0 || n >= s->numVertices())
|
|
ThrowRuntimeException("Vertex index out of range");
|
|
}
|
|
}
|
|
static inline void debugVertex(Surface* s, int n, int t)
|
|
{
|
|
if (debug) {
|
|
debug3d();
|
|
if (n < 0 || n >= s->numVertices())
|
|
ThrowRuntimeException("Vertex index out of range");
|
|
if (t < 0 || t > 1)
|
|
ThrowRuntimeException("Texture coordinate set out of range");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static Entity* loadEntity(std::string t, int hint)
|
|
{
|
|
t = tolower(t);
|
|
int n = t.rfind(".");
|
|
if (n == std::string::npos)
|
|
return 0;
|
|
std::string ext = t.substr(n + 1);
|
|
MeshLoader* l;
|
|
|
|
if (ext == "x") {
|
|
//l = &Loader_X;
|
|
} else if (ext == "3ds") {
|
|
l = &loader_3ds;
|
|
} else if (ext == "b3d") {
|
|
l = &loader_b3d;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
const Transform& conv = loader_mat_map[ext];
|
|
|
|
CachedTexture::setPath(filenamepath(t));
|
|
Entity* e = l->load(t, conv, hint);
|
|
CachedTexture::setPath("");
|
|
return e;
|
|
}
|
|
|
|
static void collapseMesh(MeshModel* mesh, Entity* e)
|
|
{
|
|
while (e->GetChildren()) {
|
|
collapseMesh(mesh, e->GetChildren());
|
|
}
|
|
if (Model* p = e->getModel()) {
|
|
if (MeshModel* t = p->getMeshModel()) {
|
|
t->transform(e->GetWorldTransform());
|
|
mesh->add(*t);
|
|
}
|
|
}
|
|
delete e;
|
|
}
|
|
|
|
static void insert(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug)
|
|
entity_set.insert(e);
|
|
#endif
|
|
e->SetVisible(true);
|
|
e->SetEnabled(true);
|
|
e->getObject()->reset();
|
|
for (Entity* p = e->GetChildren(); p; p = p->GetSuccessor()) {
|
|
insert(p);
|
|
}
|
|
}
|
|
|
|
static Entity* insertEntity(Entity* e, Entity* p)
|
|
{
|
|
e->SetParent(p);
|
|
insert(e);
|
|
return e;
|
|
}
|
|
|
|
static void erase(Entity* e)
|
|
{
|
|
for (Entity* p = e->GetChildren(); p; p = p->GetSuccessor()) {
|
|
erase(p);
|
|
}
|
|
if (e->getListener())
|
|
listener = 0;
|
|
#ifdef _DEBUG
|
|
if (debug)
|
|
entity_set.erase(e);
|
|
#endif
|
|
}
|
|
|
|
static Entity* findChild(Entity* e, const std::string& t)
|
|
{
|
|
if (e->getName() == t)
|
|
return e;
|
|
for (Entity* p = e->GetChildren(); p; p = p->GetSuccessor()) {
|
|
if (Entity* q = findChild(p, t))
|
|
return q;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////
|
|
// GLOBAL WORLD COMMANDS //
|
|
///////////////////////////
|
|
void bbLoaderMatrix(BBStr* ext, float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy,
|
|
float zz)
|
|
{
|
|
loader_mat_map.erase(*ext);
|
|
loader_mat_map[*ext] = Transform(Matrix(Vector(xx, xy, xz), Vector(yx, yy, yz), Vector(zx, zy, zz)));
|
|
delete ext;
|
|
}
|
|
|
|
int bbHWTexUnits()
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
return gx_scene->hwTexUnits();
|
|
}
|
|
|
|
int bbGfxDriverCaps3D()
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
return gx_scene->gfxDriverCaps3D();
|
|
}
|
|
|
|
void bbHWMultiTex(int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
gx_scene->setHWMultiTex(!!enable);
|
|
}
|
|
|
|
void bbWBuffer(int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
gx_scene->setWBuffer(!!enable);
|
|
}
|
|
|
|
void bbDither(int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
gx_scene->setDither(!!enable);
|
|
}
|
|
|
|
void bbAntiAlias(int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
gx_scene->setAntialias(!!enable);
|
|
}
|
|
|
|
void bbWireFrame(int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
gx_scene->setWireframe(!!enable);
|
|
}
|
|
|
|
void bbAmbientLight(float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Vector t(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat);
|
|
gx_scene->setAmbient(&(t.x));
|
|
}
|
|
|
|
void bbClearCollisions()
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
world->clearCollisions();
|
|
}
|
|
|
|
void bbCollisions(int src_type, int dest_type, int method, int response)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
world->addCollision(src_type, dest_type, method, response);
|
|
}
|
|
|
|
static int update_ms;
|
|
|
|
void bbUpdateWorld(float elapsed)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
|
|
#ifndef BETA
|
|
world->update(elapsed);
|
|
return;
|
|
#endif
|
|
|
|
update_ms = gx_runtime->getMilliSecs();
|
|
world->update(elapsed);
|
|
update_ms = gx_runtime->getMilliSecs() - update_ms;
|
|
}
|
|
|
|
void bbCaptureWorld()
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
world->capture();
|
|
}
|
|
|
|
void bbRenderWorld(float tween)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
|
|
#ifndef BETA
|
|
tri_count = gx_scene->getTrianglesDrawn();
|
|
world->render(tween);
|
|
tri_count = gx_scene->getTrianglesDrawn() - tri_count;
|
|
return;
|
|
#else
|
|
int tris = gx_scene->getTrianglesDrawn();
|
|
int render_ms = gx_runtime->getMilliSecs();
|
|
world->render(tween);
|
|
render_ms = gx_runtime->getMilliSecs() - render_ms;
|
|
|
|
extern int bbKeyHit(int);
|
|
extern void bbDelay(int);
|
|
bbDelay(0);
|
|
if (bbKeyHit(0x57)) {
|
|
stats_mode = !stats_mode;
|
|
}
|
|
if (bbKeyHit(0x58)) {
|
|
static int n;
|
|
string t = "screenshot" + itoa(++n) + ".bmp";
|
|
bbSaveBuffer(bbBackBuffer(), new BBStr(t));
|
|
}
|
|
|
|
if (!stats_mode)
|
|
return;
|
|
|
|
tris = gx_scene->getTrianglesDrawn() - tris;
|
|
|
|
static int time;
|
|
int frame_ms = gx_runtime->getMilliSecs() - time;
|
|
time += frame_ms;
|
|
|
|
int fps = frame_ms ? 1000 / frame_ms : 1000;
|
|
int ups = update_ms ? 1000 / update_ms : 1000;
|
|
int rps = render_ms ? 1000 / render_ms : 1000;
|
|
|
|
string t_fps = "000" + itoa(fps);
|
|
t_fps = t_fps.substr(t_fps.size() - 4);
|
|
string t_ups = "000" + itoa(ups);
|
|
t_ups = t_ups.substr(t_ups.size() - 4);
|
|
string t_rps = "000" + itoa(rps);
|
|
t_rps = t_rps.substr(t_rps.size() - 4);
|
|
string t_tris = "00000" + itoa(tris);
|
|
t_tris = t_tris.substr(t_tris.size() - 6);
|
|
|
|
string t = "FPS:" + t_fps + " UPS:" + t_ups + " RPS:" + t_rps + " TRIS:" + t_tris;
|
|
|
|
bbText(0, bbGraphicsHeight() - bbFontHeight(), new BBStr(t), 0, 0);
|
|
#endif
|
|
}
|
|
|
|
int bbTrisRendered()
|
|
{
|
|
return tri_count;
|
|
}
|
|
|
|
float bbStats3D(int n)
|
|
{
|
|
return stats3d[n];
|
|
}
|
|
|
|
//////////////////////
|
|
// TEXTURE COMMANDS //
|
|
//////////////////////
|
|
|
|
//Note: modify canvas->backup() to NOT release backup image!
|
|
//
|
|
Texture* bbLoadTexture(BBStr* file, int flags)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Texture* t = new Texture(*file, flags);
|
|
delete file;
|
|
if (!t->getCanvas(0)) {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
texture_set.insert(t);
|
|
return t;
|
|
}
|
|
|
|
Texture* bbLoadAnimTexture(BBStr* file, int flags, int w, int h, int first, int cnt)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Texture* t = new Texture(*file, flags, w, h, first, cnt);
|
|
delete file;
|
|
if (!t->getCanvas(0)) {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
texture_set.insert(t);
|
|
return t;
|
|
}
|
|
|
|
Texture* bbCreateTexture(int w, int h, int flags, int frames)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debug3d();
|
|
if (frames <= 0) {
|
|
ThrowRuntimeException("Illegal number of texture frames");
|
|
}
|
|
}
|
|
#endif
|
|
Texture* t = new Texture(w, h, flags, frames);
|
|
texture_set.insert(t);
|
|
return t;
|
|
}
|
|
|
|
void bbFreeTexture(Texture* t)
|
|
{
|
|
if (!t)
|
|
return;
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
if (texture_set.erase(t))
|
|
delete t;
|
|
}
|
|
|
|
void bbTextureBlend(Texture* t, int blend)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
t->setBlend(blend);
|
|
}
|
|
|
|
void bbTextureCoords(Texture* t, int flags)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
t->setFlags(flags);
|
|
}
|
|
|
|
void bbScaleTexture(Texture* t, float u_scale, float v_scale)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
t->setScale(1 / u_scale, 1 / v_scale);
|
|
}
|
|
|
|
void bbRotateTexture(Texture* t, float angle)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
t->setRotation(-angle * s_degreesToRadians);
|
|
}
|
|
|
|
void bbPositionTexture(Texture* t, float u_pos, float v_pos)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
t->setPosition(-u_pos, -v_pos);
|
|
}
|
|
|
|
int bbTextureWidth(Texture* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
return t->getCanvas(0)->getWidth();
|
|
}
|
|
|
|
int bbTextureHeight(Texture* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
return t->getCanvas(0)->getHeight();
|
|
}
|
|
|
|
BBStr* bbTextureName(Texture* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
CachedTexture* c = t->getCachedTexture();
|
|
return c ? new BBStr(c->getName().c_str()) : new BBStr("");
|
|
}
|
|
|
|
void bbSetCubeFace(Texture* t, int face)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
if (gxCanvas* c = t->getCanvas(0)) {
|
|
c->setCubeFace(face);
|
|
}
|
|
}
|
|
|
|
void bbSetCubeMode(Texture* t, int mode)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
if (gxCanvas* c = t->getCanvas(0)) {
|
|
c->setCubeMode(mode);
|
|
}
|
|
}
|
|
|
|
gxCanvas* bbTextureBuffer(Texture* t, int frame)
|
|
{
|
|
//v1.04
|
|
#ifdef _DEBUG
|
|
debugTexture(t);
|
|
#endif
|
|
if (gxCanvas* c = t->getCanvas(frame)) {
|
|
if (c->getDepth())
|
|
return c;
|
|
}
|
|
return 0;
|
|
/*
|
|
//v1.03 crashes if t->getCanvas returns null!
|
|
debugTexture(t);
|
|
gxCanvas *c=t->getCanvas( frame );
|
|
if( c->getDepth() ) return c;
|
|
return 0;
|
|
*/
|
|
}
|
|
|
|
void bbClearTextureFilters()
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Texture::clearFilters();
|
|
}
|
|
|
|
void bbTextureFilter(BBStr* t, int flags)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Texture::addFilter(*t, flags);
|
|
delete t;
|
|
}
|
|
|
|
////////////////////
|
|
// BRUSH COMMANDS //
|
|
////////////////////
|
|
Brush* bbCreateBrush(float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Brush* br = new Brush();
|
|
br->setColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
brush_set.insert(br);
|
|
return br;
|
|
}
|
|
|
|
Brush* bbLoadBrush(BBStr* file, int flags, float u_scale, float v_scale)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
Texture t(*file, flags);
|
|
delete file;
|
|
if (!t.getCanvas(0))
|
|
return 0;
|
|
if (u_scale != 1 || v_scale != 1)
|
|
t.setScale(1 / u_scale, 1 / v_scale);
|
|
Brush* br = bbCreateBrush(255, 255, 255);
|
|
br->setTexture(0, t, 0);
|
|
delete file;
|
|
return br;
|
|
}
|
|
|
|
void bbFreeBrush(Brush* b)
|
|
{
|
|
if (!b)
|
|
return;
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
if (brush_set.erase(b))
|
|
delete b;
|
|
}
|
|
|
|
void bbBrushColor(Brush* br, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(br);
|
|
#endif
|
|
br->setColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbBrushAlpha(Brush* b, float alpha)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
b->setAlpha(alpha);
|
|
}
|
|
|
|
void bbBrushShininess(Brush* b, float n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
b->setShininess(n);
|
|
}
|
|
|
|
void bbBrushTexture(Brush* b, Texture* t, int frame, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
debugTexture(t);
|
|
#endif
|
|
b->setTexture(index, *t, frame);
|
|
}
|
|
|
|
Texture* bbGetBrushTexture(Brush* b, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
Texture* tex = new Texture(b->getTexture(index));
|
|
texture_set.insert(tex);
|
|
return tex;
|
|
}
|
|
|
|
void bbBrushBlend(Brush* b, int blend)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
b->setBlend(blend);
|
|
}
|
|
|
|
void bbBrushFX(Brush* b, int fx)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
b->setFX(fx);
|
|
}
|
|
|
|
///////////////////
|
|
// MESH COMMANDS //
|
|
///////////////////
|
|
Entity* bbCreateMesh(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
MeshModel* m = new MeshModel();
|
|
return insertEntity(m, p);
|
|
}
|
|
|
|
Entity* bbLoadMesh(BBStr* f, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Entity* e = loadEntity(f->c_str(), MeshLoader::HINT_COLLAPSE);
|
|
delete f;
|
|
|
|
if (!e)
|
|
return 0;
|
|
MeshModel* m = new MeshModel();
|
|
collapseMesh(m, e);
|
|
return insertEntity(m, p);
|
|
}
|
|
|
|
Entity* bbLoadAnimMesh(BBStr* f, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Entity* e = loadEntity(f->c_str(), 0);
|
|
delete f;
|
|
|
|
if (!e)
|
|
return 0;
|
|
if (Animator* anim = e->getObject()->getAnimator()) {
|
|
anim->animate(1, 0, 0, 0);
|
|
}
|
|
return insertEntity(e, p);
|
|
}
|
|
|
|
Entity* bbCreateCube(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Entity* e = MeshUtil::createCube(Brush());
|
|
return insertEntity(e, p);
|
|
}
|
|
|
|
Entity* bbCreateSphere(int segs, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugParent(p);
|
|
if (segs < 2 || segs > 100)
|
|
ThrowRuntimeException("Illegal number of segments");
|
|
}
|
|
#endif
|
|
Entity* e = MeshUtil::createSphere(Brush(), segs);
|
|
return insertEntity(e, p);
|
|
}
|
|
|
|
Entity* bbCreateCylinder(int segs, int solid, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugParent(p);
|
|
if (segs < 3 || segs > 100)
|
|
ThrowRuntimeException("Illegal number of segments");
|
|
}
|
|
#endif
|
|
Entity* e = MeshUtil::createCylinder(Brush(), segs, !!solid);
|
|
return insertEntity(e, p);
|
|
}
|
|
|
|
Entity* bbCreateCone(int segs, int solid, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugParent(p);
|
|
if (segs < 3 || segs > 100)
|
|
ThrowRuntimeException("Illegal number of segments");
|
|
}
|
|
#endif
|
|
Entity* e = MeshUtil::createCone(Brush(), segs, !!solid);
|
|
return insertEntity(e, p);
|
|
}
|
|
|
|
Entity* bbCopyMesh(MeshModel* m, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
debugParent(p);
|
|
#endif
|
|
|
|
MeshModel* t = new MeshModel();
|
|
t->add(*m);
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbScaleMesh(MeshModel* m, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->transform(scaleMatrix(x, y, z));
|
|
}
|
|
|
|
void bbRotateMesh(MeshModel* m, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->transform(rotationMatrix(x * s_degreesToRadians, y * s_degreesToRadians, z * s_degreesToRadians));
|
|
}
|
|
|
|
void bbPositionMesh(MeshModel* m, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->transform(Vector(x, y, z));
|
|
}
|
|
|
|
void bbFitMesh(MeshModel* m, float x, float y, float z, float w, float h, float d, int uniform)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
Box box(Vector(x, y, z));
|
|
box.update(Vector(x + w, y + h, z + d));
|
|
const Box& curr_box = m->getBox();
|
|
float x_scale = box.width() / curr_box.width();
|
|
float y_scale = box.height() / curr_box.height();
|
|
float z_scale = box.depth() / curr_box.depth();
|
|
Transform t;
|
|
if (uniform) {
|
|
if (x_scale < y_scale && x_scale < z_scale) {
|
|
y_scale = z_scale = x_scale;
|
|
} else if (y_scale < x_scale && y_scale < z_scale) {
|
|
x_scale = z_scale = y_scale;
|
|
} else {
|
|
x_scale = y_scale = z_scale;
|
|
}
|
|
}
|
|
t.m.i.x = x_scale;
|
|
t.m.j.y = y_scale;
|
|
t.m.k.z = z_scale;
|
|
t.v = box.centre() - t.m * curr_box.centre();
|
|
m->transform(t);
|
|
}
|
|
|
|
void bbFlipMesh(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->flipTriangles();
|
|
}
|
|
|
|
void bbPaintMesh(MeshModel* m, Brush* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(m);
|
|
debugBrush(b);
|
|
}
|
|
#endif
|
|
m->paint(*b);
|
|
}
|
|
|
|
void bbAddMesh(MeshModel* src, MeshModel* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(src);
|
|
debugMesh(dest);
|
|
if (src == dest)
|
|
ThrowRuntimeException("A mesh cannot be added to itself");
|
|
}
|
|
#endif
|
|
dest->add(*src);
|
|
}
|
|
|
|
void bbUpdateNormals(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->updateNormals();
|
|
}
|
|
|
|
void bbLightMesh(MeshModel* m, float r, float g, float b, float range, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
MeshUtil::lightMesh(m, Vector(x, y, z), Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat), range);
|
|
}
|
|
|
|
float bbMeshWidth(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
return m->getBox().width();
|
|
}
|
|
|
|
float bbMeshHeight(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
return m->getBox().height();
|
|
}
|
|
|
|
float bbMeshDepth(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
return m->getBox().depth();
|
|
}
|
|
|
|
int bbMeshesIntersect(MeshModel* a, MeshModel* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(a);
|
|
debugMesh(b);
|
|
}
|
|
#endif
|
|
return a->intersects(*b);
|
|
}
|
|
|
|
int bbCountSurfaces(MeshModel* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
return m->getSurfaces().size();
|
|
}
|
|
|
|
Surface* bbGetSurface(MeshModel* m, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(m);
|
|
if ((size_t)index < 1 || index > m->getSurfaces().size()) {
|
|
ThrowRuntimeException("Surface Index out of range");
|
|
}
|
|
}
|
|
#endif
|
|
return m->getSurfaces()[index - 1];
|
|
}
|
|
|
|
void bbMeshCullBox(MeshModel* m, float x, float y, float z, float width, float height, float depth)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMesh(m);
|
|
#endif
|
|
m->setCullBox(Box(Vector(x, y, z), Vector(x + width, y + height, z + depth)));
|
|
}
|
|
|
|
//////////////////////
|
|
// SURFACE COMMANDS //
|
|
//////////////////////
|
|
Surface* bbFindSurface(MeshModel* m, Brush* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(m);
|
|
debugBrush(b);
|
|
}
|
|
#endif
|
|
return m->findSurface(*b);
|
|
}
|
|
|
|
Surface* bbCreateSurface(MeshModel* m, Brush* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugMesh(m);
|
|
if (b)
|
|
debugBrush(b);
|
|
}
|
|
#endif
|
|
Surface* s = b ? m->createSurface(*b) : m->createSurface(Brush());
|
|
return s;
|
|
}
|
|
|
|
Brush* bbGetSurfaceBrush(Surface* s)
|
|
{
|
|
Brush* br = new Brush(s->getBrush());
|
|
brush_set.insert(br);
|
|
return br;
|
|
}
|
|
|
|
Brush* bbGetEntityBrush(Model* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
Brush* br = new Brush(m->getBrush());
|
|
brush_set.insert(br);
|
|
return br;
|
|
}
|
|
|
|
void bbClearSurface(Surface* s, int verts, int tris)
|
|
{
|
|
s->clear(!!verts, !!tris);
|
|
}
|
|
|
|
void bbPaintSurface(Surface* s, Brush* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBrush(b);
|
|
#endif
|
|
s->setBrush(*b);
|
|
}
|
|
|
|
int bbAddVertex(Surface* s, float x, float y, float z, float tu, float tv, float tw)
|
|
{
|
|
Surface::Vertex v;
|
|
v.coords = Vector(x, y, z);
|
|
v.color = 0xffffffff;
|
|
v.tex_coords[0][0] = v.tex_coords[1][0] = tu;
|
|
v.tex_coords[0][1] = v.tex_coords[1][1] = tv;
|
|
s->addVertex(v);
|
|
return s->numVertices() - 1;
|
|
}
|
|
|
|
int bbAddTriangle(Surface* s, int v0, int v1, int v2)
|
|
{
|
|
Surface::Triangle t;
|
|
t.verts[0] = v0;
|
|
t.verts[1] = v1;
|
|
t.verts[2] = v2;
|
|
s->addTriangle(t);
|
|
return s->numTriangles() - 1;
|
|
}
|
|
|
|
void bbVertexCoords(Surface* s, int n, float x, float y, float z)
|
|
{
|
|
s->setCoords(n, Vector(x, y, z));
|
|
}
|
|
|
|
void bbVertexNormal(Surface* s, int n, float x, float y, float z)
|
|
{
|
|
s->setNormal(n, Vector(x, y, z));
|
|
}
|
|
|
|
void bbVertexColor(Surface* s, int n, float r, float g, float b, float a)
|
|
{
|
|
if (r < 0)
|
|
r = 0;
|
|
else if (r > 255)
|
|
r = 255;
|
|
if (g < 0)
|
|
g = 0;
|
|
else if (g > 255)
|
|
g = 255;
|
|
if (b < 0)
|
|
b = 0;
|
|
else if (b > 255)
|
|
b = 255;
|
|
a *= 255;
|
|
if (a < 0)
|
|
a = 0;
|
|
else if (a > 255)
|
|
a = 255;
|
|
s->setColor(n, (int(a) << 24) | (int(r) << 16) | (int(g) << 8) | int(b));
|
|
}
|
|
|
|
void bbVertexTexCoords(Surface* s, int n, float u, float v, float w, int set)
|
|
{
|
|
s->setTexCoords(n, Vector(u, v, w), set);
|
|
}
|
|
|
|
int bbCountVertices(Surface* s)
|
|
{
|
|
return s->numVertices();
|
|
}
|
|
|
|
int bbCountTriangles(Surface* s)
|
|
{
|
|
return s->numTriangles();
|
|
}
|
|
|
|
float bbVertexX(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).coords.x;
|
|
}
|
|
float bbVertexY(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).coords.y;
|
|
}
|
|
float bbVertexZ(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).coords.z;
|
|
}
|
|
float bbVertexNX(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).normal.x;
|
|
}
|
|
float bbVertexNY(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).normal.y;
|
|
}
|
|
float bbVertexNZ(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return s->getVertex(n).normal.z;
|
|
}
|
|
float bbVertexRed(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return (float)((s->getVertex(n).color & 0xff0000) >> 16);
|
|
}
|
|
float bbVertexGreen(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return (float)((s->getVertex(n).color & 0xff00) >> 8);
|
|
}
|
|
float bbVertexBlue(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return (float)(s->getVertex(n).color & 0xff);
|
|
}
|
|
float bbVertexAlpha(Surface* s, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n);
|
|
#endif
|
|
return (float)(((s->getVertex(n).color & 0xff000000) >> 24) / 255.0f);
|
|
}
|
|
float bbVertexU(Surface* s, int n, int t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n, t);
|
|
#endif
|
|
return s->getVertex(n).tex_coords[t][0];
|
|
}
|
|
float bbVertexV(Surface* s, int n, int t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n, t);
|
|
#endif
|
|
return s->getVertex(n).tex_coords[t][1];
|
|
}
|
|
float bbVertexW(Surface* s, int n, int t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugVertex(s, n, t);
|
|
#endif
|
|
return 1;
|
|
}
|
|
int bbTriangleVertex(Surface* s, int n, int v)
|
|
{
|
|
return s->getTriangle(n).verts[v];
|
|
}
|
|
|
|
/////////////////////
|
|
// CAMERA COMMANDS //
|
|
/////////////////////
|
|
Entity* bbCreateCamera(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
int x, y, w, h;
|
|
gx_canvas->getViewport(&x, &y, &w, &h);
|
|
Camera* c = new Camera();
|
|
c->setViewport(x, y, w, h);
|
|
return insertEntity(c, p);
|
|
}
|
|
|
|
void bbCameraZoom(Camera* c, float zoom)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setZoom(zoom);
|
|
}
|
|
|
|
void bbCameraRange(Camera* c, float nr, float fr)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setRange(nr, fr);
|
|
}
|
|
|
|
void bbCameraClsColor(Camera* c, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setClsColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbCameraClsMode(Camera* c, int cls_color, int cls_zbuffer)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setClsMode(cls_color ? true : false, cls_zbuffer ? true : false);
|
|
}
|
|
|
|
void bbCameraProjMode(Camera* c, int mode)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setProjMode(mode);
|
|
}
|
|
|
|
void bbCameraViewport(Camera* c, int x, int y, int w, int h)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setViewport(x, y, w, h);
|
|
}
|
|
|
|
void bbCameraFogRange(Camera* c, float nr, float fr)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setFogRange(nr, fr);
|
|
}
|
|
|
|
void bbCameraFogColor(Camera* c, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setFogColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbCameraFogMode(Camera* c, int mode)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
c->setFogMode(mode);
|
|
}
|
|
|
|
int bbCameraProject(Camera* c, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
Vector v = -c->GetWorldTransform() * Vector(x, y, z);
|
|
const Frustum& f = c->getFrustum();
|
|
if (c->getProjMode() == Camera::PROJ_ORTHO) {
|
|
int vp_x, vp_y, vp_w, vp_h;
|
|
c->getViewport(&vp_x, &vp_y, &vp_w, &vp_h);
|
|
float nr = c->getFrustumNear();
|
|
float fr = c->getFrustumFar();
|
|
float nr_w = c->getFrustumWidth();
|
|
float nr_h = c->getFrustumHeight();
|
|
projected = Vector((v.x / nr_w + .5f) * vp_w, (.5f - v.y / nr_h) * vp_h, nr);
|
|
return 1;
|
|
}
|
|
if (v.z > 0) {
|
|
float fr = +f.getPlane(Frustum::PLANE_FAR).d;
|
|
if (v.z <= fr) {
|
|
int vp_x, vp_y, vp_w, vp_h;
|
|
c->getViewport(&vp_x, &vp_y, &vp_w, &vp_h);
|
|
float nr = c->getFrustumNear();
|
|
float fr = c->getFrustumFar();
|
|
float nr_w = c->getFrustumWidth();
|
|
float nr_h = c->getFrustumHeight();
|
|
projected = Vector((v.x * nr / v.z / nr_w + .5f) * vp_w, (.5f - v.y * nr / v.z / nr_h) * vp_h, nr);
|
|
return 1;
|
|
}
|
|
}
|
|
projected = Vector();
|
|
return 0;
|
|
}
|
|
|
|
float bbProjectedX()
|
|
{
|
|
return projected.x;
|
|
}
|
|
|
|
float bbProjectedY()
|
|
{
|
|
return projected.y;
|
|
}
|
|
|
|
float bbProjectedZ()
|
|
{
|
|
return projected.z;
|
|
}
|
|
|
|
static Object* doPick(const Line& l, float radius)
|
|
{
|
|
picked.collision.time = 1;
|
|
return world->traceRay(l, radius, &picked);
|
|
}
|
|
|
|
Entity* bbCameraPick(Camera* c, float x, float y)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugCamera(c);
|
|
#endif
|
|
|
|
int vp_x, vp_y, vp_w, vp_h;
|
|
c->getViewport(&vp_x, &vp_y, &vp_w, &vp_h);
|
|
float nr = c->getFrustumNear();
|
|
float fr = c->getFrustumFar();
|
|
float nr_w = c->getFrustumWidth();
|
|
float nr_h = c->getFrustumHeight();
|
|
|
|
x = ((x / vp_w) - .5f) * nr_w;
|
|
y = (.5f - (y / vp_h)) * nr_h;
|
|
|
|
Line l;
|
|
if (c->getProjMode() == Camera::PROJ_ORTHO) {
|
|
l = c->GetWorldTransform() * Line(Vector(x, y, 0), Vector(0, 0, fr)); //x,y,fr) );
|
|
} else {
|
|
x /= nr;
|
|
y /= nr;
|
|
l = c->GetWorldTransform() * Line(Vector(), Vector(x * fr, y * fr, fr));
|
|
}
|
|
|
|
return doPick(l, 0);
|
|
}
|
|
|
|
Entity* bbLinePick(float x, float y, float z, float dx, float dy, float dz, float radius)
|
|
{
|
|
#ifdef _DEBUG
|
|
debug3d();
|
|
#endif
|
|
|
|
Line l(Vector(x, y, z), Vector(dx, dy, dz));
|
|
|
|
return doPick(l, radius);
|
|
}
|
|
|
|
Entity* bbEntityPick(Object* src, float range)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(src);
|
|
#endif
|
|
|
|
Line l(src->GetWorldPosition(), src->GetWorldTransform().m.k * range);
|
|
|
|
return doPick(l, 0);
|
|
}
|
|
|
|
int bbEntityVisible(Object* src, Object* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugObject(src);
|
|
debugObject(dest);
|
|
}
|
|
#endif
|
|
|
|
return world->CheckLineOfSight(src, dest) ? 1 : 0;
|
|
}
|
|
|
|
int bbEntityInView(Entity* e, Camera* c)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(e);
|
|
debugCamera(c);
|
|
}
|
|
#endif
|
|
if (Model* p = e->getModel()) {
|
|
if (MeshModel* m = p->getMeshModel()) {
|
|
const Box& b = m->getBox();
|
|
Transform t = -c->GetWorldTransform() * e->GetWorldTransform();
|
|
Vector p[] = {t * b.corner(0), t * b.corner(1), t * b.corner(2), t * b.corner(3),
|
|
t * b.corner(4), t * b.corner(5), t * b.corner(6), t * b.corner(7)};
|
|
return c->getFrustum().cull(p, 8);
|
|
}
|
|
}
|
|
Vector p[] = {-c->GetWorldTransform() * e->GetWorldPosition()};
|
|
return c->getFrustum().cull(p, 1);
|
|
}
|
|
|
|
float bbPickedX()
|
|
{
|
|
return picked.coords.x;
|
|
}
|
|
|
|
float bbPickedY()
|
|
{
|
|
return picked.coords.y;
|
|
}
|
|
|
|
float bbPickedZ()
|
|
{
|
|
return picked.coords.z;
|
|
}
|
|
|
|
float bbPickedNX()
|
|
{
|
|
return picked.collision.normal.x;
|
|
}
|
|
|
|
float bbPickedNY()
|
|
{
|
|
return picked.collision.normal.y;
|
|
}
|
|
|
|
float bbPickedNZ()
|
|
{
|
|
return picked.collision.normal.z;
|
|
}
|
|
|
|
float bbPickedTime()
|
|
{
|
|
return picked.collision.time;
|
|
}
|
|
|
|
Object* bbPickedEntity()
|
|
{
|
|
return picked.with;
|
|
}
|
|
|
|
void* bbPickedSurface()
|
|
{
|
|
return picked.collision.surface;
|
|
}
|
|
|
|
int bbPickedTriangle()
|
|
{
|
|
return picked.collision.index;
|
|
}
|
|
|
|
////////////////////
|
|
// LIGHT COMMANDS //
|
|
////////////////////
|
|
Entity* bbCreateLight(int type, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Light* t = new Light(type);
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbLightColor(Light* light, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugLight(light);
|
|
#endif
|
|
light->setColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbLightRange(Light* light, float range)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugLight(light);
|
|
#endif
|
|
light->setRange(range);
|
|
}
|
|
|
|
void bbLightConeAngles(Light* light, float inner, float outer)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugLight(light);
|
|
#endif
|
|
inner *= s_degreesToRadians;
|
|
outer *= s_degreesToRadians;
|
|
if (inner < 0)
|
|
inner = 0;
|
|
else if (inner > PI)
|
|
inner = PI;
|
|
if (outer < inner)
|
|
outer = inner;
|
|
else if (outer > PI)
|
|
outer = PI;
|
|
light->setConeAngles(inner, outer);
|
|
}
|
|
|
|
////////////////////
|
|
// PIVOT COMMANDS //
|
|
////////////////////
|
|
Entity* bbCreatePivot(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Pivot* t = new Pivot();
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
/////////////////////
|
|
// SPRITE COMMANDS //
|
|
/////////////////////
|
|
Entity* bbCreateSprite(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Sprite* s = new Sprite();
|
|
s->setFX(gxScene::FX_FULLBRIGHT);
|
|
return insertEntity(s, p);
|
|
}
|
|
|
|
Entity* bbLoadSprite(BBStr* file, int flags, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Texture t(*file, flags);
|
|
delete file;
|
|
if (!t.getCanvas(0))
|
|
return 0;
|
|
Sprite* s = new Sprite();
|
|
s->setTexture(0, t, 0);
|
|
s->setFX(gxScene::FX_FULLBRIGHT);
|
|
|
|
if (flags & gxCanvas::CANVAS_TEX_MASK)
|
|
s->setBlend(gxScene::BLEND_REPLACE);
|
|
else if (flags & gxCanvas::CANVAS_TEX_ALPHA)
|
|
s->setBlend(gxScene::BLEND_ALPHA);
|
|
else
|
|
s->setBlend(gxScene::BLEND_ADD);
|
|
|
|
return insertEntity(s, p);
|
|
}
|
|
|
|
void bbRotateSprite(Sprite* s, float angle)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugSprite(s);
|
|
#endif
|
|
s->setRotation(angle * s_degreesToRadians);
|
|
}
|
|
|
|
void bbScaleSprite(Sprite* s, float x, float y)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugSprite(s);
|
|
#endif
|
|
s->setScale(x, y);
|
|
}
|
|
|
|
void bbHandleSprite(Sprite* s, float x, float y)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugSprite(s);
|
|
#endif
|
|
s->setHandle(x, y);
|
|
}
|
|
|
|
void bbSpriteViewMode(Sprite* s, int mode)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugSprite(s);
|
|
#endif
|
|
s->setViewmode(mode);
|
|
}
|
|
|
|
/////////////////////
|
|
// MIRROR COMMANDS //
|
|
/////////////////////
|
|
Entity* bbCreateMirror(Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
Mirror* t = new Mirror();
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
////////////////////
|
|
// PLANE COMMANDS //
|
|
////////////////////
|
|
Entity* bbCreatePlane(int segs, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugParent(p);
|
|
if (segs < 1 || segs > 20)
|
|
ThrowRuntimeException("Illegal number of segments");
|
|
}
|
|
#endif
|
|
PlaneModel* t = new PlaneModel(segs);
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
//////////////////
|
|
// MD2 COMMANDS //
|
|
//////////////////
|
|
Entity* bbLoadMD2(BBStr* file, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
MD2Model* t = new MD2Model(*file);
|
|
delete file;
|
|
if (!t->getValid()) {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbAnimateMD2(MD2Model* m, int mode, float speed, int first, int last, float trans)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMD2(m);
|
|
#endif
|
|
m->startMD2Anim(first, last, mode, speed, trans);
|
|
}
|
|
|
|
float bbMD2AnimTime(MD2Model* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMD2(m);
|
|
#endif
|
|
return m->getMD2AnimTime();
|
|
}
|
|
|
|
int bbMD2AnimLength(MD2Model* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMD2(m);
|
|
#endif
|
|
return m->getMD2AnimLength();
|
|
}
|
|
|
|
int bbMD2Animating(MD2Model* m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugMD2(m);
|
|
#endif
|
|
return m->getMD2Animating();
|
|
}
|
|
|
|
//////////////////
|
|
// BSP Commands //
|
|
//////////////////
|
|
Entity* bbLoadBSP(BBStr* file, float gam, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
CachedTexture::setPath(filenamepath(*file));
|
|
Q3BSPModel* t = new Q3BSPModel(*file, gam);
|
|
delete file;
|
|
CachedTexture::setPath("");
|
|
|
|
if (!t->isValid()) {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbBSPAmbientLight(Q3BSPModel* t, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBSP(t);
|
|
#endif
|
|
t->setAmbient(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbBSPLighting(Q3BSPModel* t, int lmap)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugBSP(t);
|
|
#endif
|
|
t->setLighting(!!lmap);
|
|
}
|
|
|
|
//////////////////////
|
|
// TERRAIN COMMANDS //
|
|
//////////////////////
|
|
static float terrainHeight(Terrain* t, float x, float z)
|
|
{
|
|
int ix = (int)floor(x);
|
|
int iz = (int)floor(z);
|
|
float tx = x - ix, tz = z - iz;
|
|
float h0 = t->getHeight(ix, iz);
|
|
float h1 = t->getHeight(ix + 1, iz);
|
|
float h2 = t->getHeight(ix, iz + 1);
|
|
float h3 = t->getHeight(ix + 1, iz + 1);
|
|
float ha = (h1 - h0) * tx + h0, hb = (h3 - h2) * tx + h2;
|
|
float h = (hb - ha) * tz + ha;
|
|
return h;
|
|
}
|
|
|
|
static Vector terrainVector(Terrain* t, float x, float y, float z)
|
|
{
|
|
Vector v = -t->GetWorldTransform() * Vector(x, y, z);
|
|
return t->GetWorldTransform() * Vector(v.x, terrainHeight(t, v.x, v.z), v.z);
|
|
}
|
|
|
|
Entity* bbCreateTerrain(int n, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
int shift = 0;
|
|
while ((1 << shift) < n)
|
|
++shift;
|
|
if ((1 << shift) != n)
|
|
ThrowRuntimeException("Illegal terrain size");
|
|
Terrain* t = new Terrain(shift);
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
Entity* bbLoadTerrain(BBStr* file, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugParent(p);
|
|
#endif
|
|
gxCanvas* c = gx_graphics->loadCanvas(*file, gxCanvas::CANVAS_HIGHCOLOR);
|
|
if (!c)
|
|
ThrowRuntimeException("Unable to load heightmap image");
|
|
int w = c->getWidth(), h = c->getHeight();
|
|
if (w != h)
|
|
ThrowRuntimeException("Terrain must be square");
|
|
int shift = 0;
|
|
while ((1 << shift) < w)
|
|
++shift;
|
|
if ((1 << shift) != w)
|
|
ThrowRuntimeException("Illegal terrain size");
|
|
Terrain* t = new Terrain(shift);
|
|
c->lock();
|
|
for (int y = 0; y < h; ++y) {
|
|
for (int x = 0; x < w; ++x) {
|
|
int rgb = c->getPixelFast(x, y);
|
|
int r = (rgb >> 16) & 0xff, g = (rgb >> 8) & 0xff, b = rgb & 0xff;
|
|
float p = (r > g ? (r > b ? r : b) : (g > b ? g : b)) / 255.0f;
|
|
t->setHeight(x, h - 1 - y, p, false);
|
|
}
|
|
}
|
|
c->unlock();
|
|
gx_graphics->freeCanvas(c);
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbTerrainDetail(Terrain* t, int n, int m)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
t->setDetail(n, !!m);
|
|
}
|
|
|
|
void bbTerrainShading(Terrain* t, int enable)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
t->setShading(!!enable);
|
|
}
|
|
|
|
float bbTerrainX(Terrain* t, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
return terrainVector(t, x, y, z).x;
|
|
}
|
|
|
|
float bbTerrainY(Terrain* t, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
return terrainVector(t, x, y, z).y;
|
|
}
|
|
|
|
float bbTerrainZ(Terrain* t, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
return terrainVector(t, x, y, z).z;
|
|
}
|
|
|
|
int bbTerrainSize(Terrain* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
return t->getSize();
|
|
}
|
|
|
|
float bbTerrainHeight(Terrain* t, int x, int z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
return t->getHeight(x, z);
|
|
}
|
|
|
|
void bbModifyTerrain(Terrain* t, int x, int z, float h, int realtime)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugTerrain(t);
|
|
#endif
|
|
t->setHeight(x, z, h, !!realtime);
|
|
}
|
|
|
|
////////////////////
|
|
// AUDIO COMMANDS //
|
|
////////////////////
|
|
Entity* bbCreateListener(Entity* p, float roll, float dopp, float dist)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugParent(p);
|
|
if (listener)
|
|
ThrowRuntimeException("Listener already created");
|
|
}
|
|
#endif
|
|
listener = new Listener(roll, dopp, dist);
|
|
return insertEntity(listener, p);
|
|
}
|
|
|
|
gxChannel* bbEmitSound(gxSound* sound, Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugObject(o);
|
|
if (!listener)
|
|
ThrowRuntimeException("No Listener created");
|
|
}
|
|
#endif
|
|
return o->emitSound(sound);
|
|
}
|
|
|
|
/////////////////////
|
|
// ENTITY COMMANDS //
|
|
/////////////////////
|
|
Entity* bbCopyEntity(Entity* e, Entity* p)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(e);
|
|
debugParent(p);
|
|
}
|
|
#endif
|
|
Entity* t = e->getObject()->copy();
|
|
if (!t)
|
|
return 0;
|
|
return insertEntity(t, p);
|
|
}
|
|
|
|
void bbFreeEntity(Entity* e)
|
|
{
|
|
if (!e)
|
|
return;
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(e);
|
|
erase(e);
|
|
}
|
|
#endif
|
|
delete e;
|
|
}
|
|
|
|
void bbHideEntity(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
e->SetEnabled(false);
|
|
e->SetVisible(false);
|
|
}
|
|
|
|
void bbShowEntity(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
e->SetVisible(true);
|
|
e->SetEnabled(true);
|
|
e->getObject()->reset();
|
|
}
|
|
|
|
void bbEntityParent(Entity* e, Entity* p, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(e);
|
|
debugParent(p);
|
|
Entity* t = p;
|
|
while (t) {
|
|
if (t == e) {
|
|
ThrowRuntimeException("Entity cannot be parented to itself!");
|
|
}
|
|
t = t->getParent();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (e->getParent() == p)
|
|
return;
|
|
|
|
if (global) {
|
|
Transform t = e->GetWorldTransform();
|
|
e->SetParent(p);
|
|
e->SetWorldTransform(t);
|
|
} else {
|
|
e->SetParent(p);
|
|
e->getObject()->reset();
|
|
}
|
|
}
|
|
|
|
int bbCountChildren(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
int n = 0;
|
|
for (Entity* p = e->GetChildren(); p; p = p->GetSuccessor())
|
|
++n;
|
|
return n;
|
|
}
|
|
|
|
Entity* bbGetChild(Entity* e, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
Entity* p = e->GetChildren();
|
|
while (--index && p)
|
|
p = p->GetSuccessor();
|
|
return p;
|
|
}
|
|
|
|
Entity* bbFindChild(Entity* e, BBStr* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
e = findChild(e, *t);
|
|
delete t;
|
|
return e;
|
|
}
|
|
|
|
////////////////////////
|
|
// ANIMATION COMMANDS //
|
|
////////////////////////
|
|
int bbLoadAnimSeq(Object* o, BBStr* f)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator()) {
|
|
Entity* t = loadEntity(f->c_str(), MeshLoader::HINT_ANIMONLY);
|
|
delete f;
|
|
if (t) {
|
|
if (Animator* p = t->getObject()->getAnimator()) {
|
|
anim->addSeqs(p);
|
|
}
|
|
delete t;
|
|
}
|
|
return anim->numSeqs() - 1;
|
|
} else {
|
|
delete f;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void bbSetAnimTime(Object* o, float time, int seq)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator()) {
|
|
anim->setAnimTime(time, seq);
|
|
} else {
|
|
ThrowRuntimeException("Entity has not animation");
|
|
}
|
|
}
|
|
|
|
void bbAnimate(Object* o, int mode, float speed, int seq, float trans)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator()) {
|
|
anim->animate(mode, speed, seq, trans);
|
|
} else {
|
|
ThrowRuntimeException("Entity has no animation");
|
|
}
|
|
}
|
|
|
|
void bbSetAnimKey(Object* o, int frame, int pos_key, int rot_key, int scl_key)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
Animation anim = o->getAnimation();
|
|
if (pos_key)
|
|
anim.setPositionKey(frame, o->GetLocalPosition());
|
|
if (rot_key)
|
|
anim.setRotationKey(frame, o->GetLocalRotation());
|
|
if (scl_key)
|
|
anim.setScaleKey(frame, o->GetLocalScale());
|
|
o->setAnimation(anim);
|
|
}
|
|
|
|
int bbExtractAnimSeq(Object* o, int first, int last, int seq)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator()) {
|
|
anim->extractSeq(first, last, seq);
|
|
return anim->numSeqs() - 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int bbAddAnimSeq(Object* o, int length)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
Animator* anim = o->getAnimator();
|
|
if (anim) {
|
|
anim->addSeq(length);
|
|
} else {
|
|
anim = new Animator(o, length);
|
|
o->setAnimator(anim);
|
|
}
|
|
return anim->numSeqs() - 1;
|
|
}
|
|
|
|
int bbAnimSeq(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator())
|
|
return anim->animSeq();
|
|
return -1;
|
|
}
|
|
|
|
float bbAnimTime(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator())
|
|
return anim->animTime();
|
|
return -1;
|
|
}
|
|
|
|
int bbAnimLength(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator())
|
|
return anim->animLen();
|
|
return -1;
|
|
}
|
|
|
|
int bbAnimating(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
if (Animator* anim = o->getAnimator())
|
|
return anim->animating();
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////
|
|
// ENTITY SPECIAL FX COMMANDS //
|
|
////////////////////////////////
|
|
void bbPaintEntity(Model* m, Brush* b)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugModel(m);
|
|
debugBrush(b);
|
|
}
|
|
#endif
|
|
m->setBrush(*b);
|
|
}
|
|
|
|
void bbEntityColor(Model* m, float r, float g, float b)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setColor(Vector(r * s_colorToFloat, g * s_colorToFloat, b * s_colorToFloat));
|
|
}
|
|
|
|
void bbEntityAlpha(Model* m, float alpha)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setAlpha(alpha);
|
|
}
|
|
|
|
void bbEntityShininess(Model* m, float shininess)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setShininess(shininess);
|
|
}
|
|
|
|
void bbEntityTexture(Model* m, Texture* t, int frame, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
debugTexture(t);
|
|
#endif
|
|
m->setTexture(index, *t, frame);
|
|
}
|
|
|
|
void bbEntityBlend(Model* m, int blend)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setBlend(blend);
|
|
}
|
|
|
|
void bbEntityFX(Model* m, int fx)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setFX(fx);
|
|
}
|
|
|
|
void bbEntityAutoFade(Model* m, float nr, float fr)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugModel(m);
|
|
#endif
|
|
m->setAutoFade(nr, fr);
|
|
}
|
|
|
|
void bbEntityOrder(Object* o, int n)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(o);
|
|
if (!o->getModel() && !o->getCamera()) {
|
|
ThrowRuntimeException("Entity is not a model or camera");
|
|
}
|
|
}
|
|
#endif
|
|
o->setOrder(n);
|
|
}
|
|
|
|
//////////////////////////////
|
|
// ENTITY PROPERTY COMMANDS //
|
|
//////////////////////////////
|
|
float bbEntityX(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return global ? e->GetWorldPosition().x : e->GetLocalPosition().x;
|
|
}
|
|
|
|
float bbEntityY(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return global ? e->GetWorldPosition().y : e->GetLocalPosition().y;
|
|
}
|
|
|
|
float bbEntityZ(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return global ? e->GetWorldPosition().z : e->GetLocalPosition().z;
|
|
}
|
|
|
|
float bbEntityPitch(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return quatPitch(global ? e->GetWorldRotation() : e->GetLocalRotation()) * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbEntityYaw(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return quatYaw(global ? e->GetWorldRotation() : e->GetLocalRotation()) * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbEntityRoll(Entity* e, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return quatRoll(global ? e->GetWorldRotation() : e->GetLocalRotation()) * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbGetMatElement(Entity* e, int row, int col)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return row < 3 ? e->GetWorldTransform().m[row][col] : e->GetWorldTransform().v[col];
|
|
}
|
|
|
|
void bbTFormPoint(float x, float y, float z, Entity* src, Entity* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
if (src)
|
|
debugEntity(src);
|
|
if (dest)
|
|
debugEntity(dest);
|
|
}
|
|
#endif
|
|
tformed = Vector(x, y, z);
|
|
if (src)
|
|
tformed = src->GetWorldTransform() * tformed;
|
|
if (dest)
|
|
tformed = -dest->GetWorldTransform() * tformed;
|
|
}
|
|
|
|
void bbTFormVector(float x, float y, float z, Entity* src, Entity* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
if (src)
|
|
debugEntity(src);
|
|
if (dest)
|
|
debugEntity(dest);
|
|
}
|
|
#endif
|
|
tformed = Vector(x, y, z);
|
|
if (src)
|
|
tformed = src->GetWorldTransform().m * tformed;
|
|
if (dest)
|
|
tformed = -dest->GetWorldTransform().m * tformed;
|
|
}
|
|
|
|
void bbTFormNormal(float x, float y, float z, Entity* src, Entity* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
if (src)
|
|
debugEntity(src);
|
|
if (dest)
|
|
debugEntity(dest);
|
|
}
|
|
#endif
|
|
tformed = Vector(x, y, z);
|
|
if (src)
|
|
tformed = (src->GetWorldTransform().m).cofactor() * tformed;
|
|
if (dest)
|
|
tformed = (-dest->GetWorldTransform().m).cofactor() * tformed;
|
|
tformed.normalize();
|
|
}
|
|
|
|
float bbTFormedX()
|
|
{
|
|
return tformed.x;
|
|
}
|
|
|
|
float bbTFormedY()
|
|
{
|
|
return tformed.y;
|
|
}
|
|
|
|
float bbTFormedZ()
|
|
{
|
|
return tformed.z;
|
|
}
|
|
|
|
float bbVectorYaw(float x, float y, float z)
|
|
{
|
|
return Vector(x, y, z).yaw() * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbVectorPitch(float x, float y, float z)
|
|
{
|
|
return Vector(x, y, z).pitch() * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbDeltaYaw(Entity* src, Entity* dest)
|
|
{
|
|
float x = src->GetWorldTransform().m.k.yaw();
|
|
float y = (dest->GetWorldTransform().v - src->GetWorldTransform().v).yaw();
|
|
float d = y - x;
|
|
if (d < -PI)
|
|
d += TWOPI;
|
|
else if (d >= PI)
|
|
d -= TWOPI;
|
|
return d * s_radiansToDegrees;
|
|
}
|
|
|
|
float bbDeltaPitch(Entity* src, Entity* dest)
|
|
{
|
|
float x = src->GetWorldTransform().m.k.pitch();
|
|
float y = (dest->GetWorldTransform().v - src->GetWorldTransform().v).pitch();
|
|
float d = y - x;
|
|
if (d < -PI)
|
|
d += TWOPI;
|
|
else if (d >= PI)
|
|
d -= TWOPI;
|
|
return d * s_radiansToDegrees;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// ENTITY COLLISION COMMANDS //
|
|
///////////////////////////////
|
|
void bbResetEntity(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
o->reset();
|
|
}
|
|
|
|
static void entityType(Entity* e, int type)
|
|
{
|
|
e->getObject()->setCollisionType(type);
|
|
e->getObject()->reset();
|
|
for (Entity* p = e->GetChildren(); p; p = p->GetSuccessor()) {
|
|
entityType(p, type);
|
|
}
|
|
}
|
|
|
|
void bbEntityType(Object* o, int type, int recurs)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugObject(o);
|
|
if (type < 0 || type > 999)
|
|
ThrowRuntimeException("EntityType ID must be in the range 0...999");
|
|
}
|
|
#endif
|
|
if (recurs)
|
|
entityType(o, type);
|
|
else {
|
|
o->setCollisionType(type);
|
|
o->reset();
|
|
}
|
|
}
|
|
|
|
void bbEntityPickMode(Object* o, int mode, int obs)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
o->setPickGeometry(mode);
|
|
o->setObscurer(!!obs);
|
|
}
|
|
|
|
Entity* bbGetParent(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return e->getParent();
|
|
}
|
|
|
|
int bbGetEntityType(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
return o->getCollisionType();
|
|
}
|
|
|
|
void bbEntityRadius(Object* o, float x_radius, float y_radius)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
Vector radii(x_radius, y_radius ? y_radius : x_radius, x_radius);
|
|
o->setCollisionRadii(radii);
|
|
}
|
|
|
|
void bbEntityBox(Object* o, float x, float y, float z, float w, float h, float d)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
Box b(Vector(x, y, z));
|
|
b.update(Vector(x + w, y + h, z + d));
|
|
o->setCollisionBox(b);
|
|
}
|
|
|
|
Object* bbEntityCollided(Object* o, int type)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
Object::Collisions::const_iterator it;
|
|
const Object::Collisions& c = o->getCollisions();
|
|
for (it = c.begin(); it != c.end(); ++it) {
|
|
const ObjCollision* c = *it;
|
|
if (c->with->getCollisionType() == type)
|
|
return c->with;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int bbCountCollisions(Object* o)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugObject(o);
|
|
#endif
|
|
return o->getCollisions().size();
|
|
}
|
|
|
|
float bbCollisionX(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->coords.x;
|
|
}
|
|
|
|
float bbCollisionY(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->coords.y;
|
|
}
|
|
|
|
float bbCollisionZ(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->coords.z;
|
|
}
|
|
|
|
float bbCollisionNX(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.normal.x;
|
|
}
|
|
|
|
float bbCollisionNY(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.normal.y;
|
|
}
|
|
|
|
float bbCollisionNZ(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.normal.z;
|
|
}
|
|
|
|
float bbCollisionTime(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.time;
|
|
}
|
|
|
|
Object* bbCollisionEntity(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->with;
|
|
}
|
|
|
|
void* bbCollisionSurface(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.surface;
|
|
}
|
|
|
|
int bbCollisionTriangle(Object* o, int index)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugColl(o, index);
|
|
#endif
|
|
return o->getCollisions()[index - 1]->collision.index;
|
|
}
|
|
|
|
float bbEntityDistance(Entity* src, Entity* dest)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(src);
|
|
debugEntity(dest);
|
|
#endif
|
|
return src->GetWorldPosition().distance(dest->GetWorldPosition());
|
|
}
|
|
|
|
////////////////////////////////////
|
|
// ENTITY TRANSFORMATION COMMANDS //
|
|
////////////////////////////////////
|
|
void bbMoveEntity(Entity* e, float x, float y, float z)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
e->SetLocalPosition(e->GetLocalPosition() + e->GetLocalRotation() * Vector(x, y, z));
|
|
}
|
|
|
|
void bbTurnEntity(Entity* e, float p, float y, float r, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
global
|
|
? e->SetWorldRotation(rotationQuat(p * s_degreesToRadians, y * s_degreesToRadians, r * s_degreesToRadians)
|
|
* e->GetWorldRotation())
|
|
: e->SetLocalRotation(e->GetLocalRotation()
|
|
* rotationQuat(p * s_degreesToRadians, y * s_degreesToRadians, r * s_degreesToRadians));
|
|
}
|
|
|
|
void bbTranslateEntity(Entity* e, float x, float y, float z, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
global ? e->SetWorldPosition(e->GetWorldPosition() + Vector(x, y, z))
|
|
: e->SetLocalPosition(e->GetLocalPosition() + Vector(x, y, z));
|
|
}
|
|
|
|
void bbPositionEntity(Entity* e, float x, float y, float z, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
global ? e->SetWorldPosition(Vector(x, y, z)) : e->SetLocalPosition(Vector(x, y, z));
|
|
}
|
|
|
|
void bbScaleEntity(Entity* e, float x, float y, float z, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
global ? e->SetWorldScale(Vector(x, y, z)) : e->SetLocalScale(Vector(x, y, z));
|
|
}
|
|
|
|
void bbRotateEntity(Entity* e, float p, float y, float r, int global)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
global ? e->SetWorldRotation(rotationQuat(p * s_degreesToRadians, y * s_degreesToRadians, r * s_degreesToRadians))
|
|
: e->SetLocalRotation(rotationQuat(p * s_degreesToRadians, y * s_degreesToRadians, r * s_degreesToRadians));
|
|
}
|
|
|
|
void bbPointEntity(Entity* e, Entity* t, float roll)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (debug) {
|
|
debugEntity(e);
|
|
debugEntity(t);
|
|
}
|
|
#endif
|
|
Vector v = t->GetWorldTransform().v - e->GetWorldTransform().v;
|
|
e->SetWorldRotation(rotationQuat(v.pitch(), v.yaw(), roll * s_degreesToRadians));
|
|
}
|
|
|
|
void bbAlignToVector(Entity* e, float nx, float ny, float nz, int axis, float rate)
|
|
{
|
|
Vector ax(nx, ny, nz);
|
|
float l = ax.length();
|
|
if (l <= FLT_EPSILON)
|
|
return;
|
|
ax /= l;
|
|
|
|
Quat q = e->GetWorldRotation();
|
|
Vector tv = (axis == 1) ? q.i() : (axis == 2 ? q.j() : q.k());
|
|
|
|
float dp = ax.dot(tv);
|
|
|
|
if (dp >= 1 - FLT_EPSILON)
|
|
return;
|
|
|
|
if (dp <= -1 + FLT_EPSILON) {
|
|
float an = PI * rate / 2;
|
|
Vector cp = (axis == 1) ? q.j() : (axis == 2 ? q.k() : q.i());
|
|
e->SetWorldRotation(Quat(cosf(an), cp * sinf(an)) * q);
|
|
return;
|
|
}
|
|
|
|
float an = acosf(dp) * rate / 2;
|
|
Vector cp = ax.cross(tv).normalized();
|
|
e->SetWorldRotation(Quat(cosf(an), cp * sinf(an)) * q);
|
|
}
|
|
|
|
//////////////////////////
|
|
// ENTITY MISC COMMANDS //
|
|
//////////////////////////
|
|
void bbNameEntity(Entity* e, BBStr* t)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
e->SetName(*t);
|
|
delete t;
|
|
}
|
|
|
|
BBStr* bbEntityName(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
return new BBStr(e->getName());
|
|
}
|
|
|
|
BBStr* bbEntityClass(Entity* e)
|
|
{
|
|
#ifdef _DEBUG
|
|
debugEntity(e);
|
|
#endif
|
|
const char* p = "Pivot";
|
|
if (e->getLight())
|
|
p = "Light";
|
|
else if (e->getCamera())
|
|
p = "Camera";
|
|
else if (e->getMirror())
|
|
p = "Mirror";
|
|
else if (e->getListener())
|
|
p = "Listener";
|
|
else if (Model* t = e->getModel()) {
|
|
if (t->getSprite())
|
|
p = "Sprite";
|
|
else if (t->getTerrain())
|
|
p = "Terrain";
|
|
else if (t->getPlaneModel())
|
|
p = "Plane";
|
|
else if (t->getMeshModel())
|
|
p = "Mesh";
|
|
else if (t->getMD2Model())
|
|
p = "MD2";
|
|
else if (t->getBSPModel())
|
|
p = "BSP";
|
|
}
|
|
return new BBStr(p);
|
|
}
|
|
|
|
void bbClearWorld(int e, int b, int t)
|
|
{
|
|
if (e) {
|
|
while (Entity::GetEntityOrphans())
|
|
bbFreeEntity(Entity::GetEntityOrphans());
|
|
}
|
|
if (b) {
|
|
while (brush_set.size())
|
|
bbFreeBrush(*brush_set.begin());
|
|
}
|
|
if (t) {
|
|
while (texture_set.size())
|
|
bbFreeTexture(*texture_set.begin());
|
|
}
|
|
}
|
|
|
|
extern int active_texs;
|
|
|
|
int bbActiveTextures()
|
|
{
|
|
return active_texs;
|
|
}
|
|
|
|
void blitz3d_open()
|
|
{
|
|
gx_scene = gx_graphics->createScene(0);
|
|
if (!gx_scene)
|
|
ThrowRuntimeException("Unable to create 3D Scene");
|
|
world = new World();
|
|
projected = Vector();
|
|
picked.collision = Collision();
|
|
picked.with = 0;
|
|
picked.coords = Vector();
|
|
Texture::clearFilters();
|
|
Texture::addFilter("", gxCanvas::CANVAS_TEX_RGB | gxCanvas::CANVAS_TEX_MIPMAP);
|
|
loader_mat_map.clear();
|
|
loader_mat_map["x"] = Transform();
|
|
loader_mat_map["3ds"] = Transform(Matrix(Vector(1, 0, 0), Vector(0, 0, 1), Vector(0, 1, 0)));
|
|
listener = 0;
|
|
stats_mode = false;
|
|
}
|
|
|
|
void blitz3d_close()
|
|
{
|
|
if (!gx_scene)
|
|
return;
|
|
bbClearWorld(1, 1, 1);
|
|
Texture::clearFilters();
|
|
loader_mat_map.clear();
|
|
delete world;
|
|
gx_graphics->freeScene(gx_scene);
|
|
gx_scene = 0;
|
|
}
|
|
|
|
bool blitz3d_create()
|
|
{
|
|
tri_count = 0;
|
|
gx_scene = 0;
|
|
world = 0;
|
|
return true;
|
|
}
|
|
|
|
bool blitz3d_destroy()
|
|
{
|
|
blitz3d_close();
|
|
return true;
|
|
}
|
|
|
|
void blitz3d_link(void (*rtSym)(const char* sym, void* pc))
|
|
{
|
|
rtSym("LoaderMatrix$file_ext#xx#xy#xz#yx#yy#yz#zx#zy#zz", bbLoaderMatrix);
|
|
rtSym("HWMultiTex%enable", bbHWMultiTex);
|
|
rtSym("%HWTexUnits", bbHWTexUnits);
|
|
rtSym("%GfxDriverCaps3D", bbGfxDriverCaps3D);
|
|
rtSym("WBuffer%enable", bbWBuffer);
|
|
rtSym("Dither%enable", bbDither);
|
|
rtSym("AntiAlias%enable", bbAntiAlias);
|
|
rtSym("WireFrame%enable", bbWireFrame);
|
|
rtSym("AmbientLight#red#green#blue", bbAmbientLight);
|
|
rtSym("ClearCollisions", bbClearCollisions);
|
|
rtSym("Collisions%source_type%destination_type%method%response", bbCollisions);
|
|
rtSym("UpdateWorld#elapsed_time=1", bbUpdateWorld);
|
|
rtSym("CaptureWorld", bbCaptureWorld);
|
|
rtSym("RenderWorld#tween=1", bbRenderWorld);
|
|
rtSym("ClearWorld%entities=1%brushes=1%textures=1", bbClearWorld);
|
|
rtSym("%ActiveTextures", bbActiveTextures);
|
|
rtSym("%TrisRendered", bbTrisRendered);
|
|
rtSym("#Stats3D%type", bbStats3D);
|
|
|
|
rtSym("%CreateTexture%width%height%flags=0%frames=1", bbCreateTexture);
|
|
rtSym("%LoadTexture$file%flags=1", bbLoadTexture);
|
|
rtSym("%LoadAnimTexture$file%flags%width%height%first%count", bbLoadAnimTexture);
|
|
rtSym("FreeTexture%texture", bbFreeTexture);
|
|
rtSym("TextureBlend%texture%blend", bbTextureBlend);
|
|
rtSym("TextureCoords%texture%coords", bbTextureCoords);
|
|
rtSym("ScaleTexture%texture#u_scale#v_scale", bbScaleTexture);
|
|
rtSym("RotateTexture%texture#angle", bbRotateTexture);
|
|
rtSym("PositionTexture%texture#u_offset#v_offset", bbPositionTexture);
|
|
rtSym("%TextureWidth%texture", bbTextureWidth);
|
|
rtSym("%TextureHeight%texture", bbTextureHeight);
|
|
rtSym("$TextureName%texture", bbTextureName);
|
|
rtSym("SetCubeFace%texture%face", bbSetCubeFace);
|
|
rtSym("SetCubeMode%texture%mode", bbSetCubeMode);
|
|
rtSym("%TextureBuffer%texture%frame=0", bbTextureBuffer);
|
|
rtSym("ClearTextureFilters", bbClearTextureFilters);
|
|
rtSym("TextureFilter$match_text%texture_flags=0", bbTextureFilter);
|
|
|
|
rtSym("%CreateBrush#red=255#green=255#blue=255", bbCreateBrush);
|
|
rtSym("%LoadBrush$file%texture_flags=1#u_scale=1#v_scale=1", bbLoadBrush);
|
|
rtSym("FreeBrush%brush", bbFreeBrush);
|
|
rtSym("BrushColor%brush#red#green#blue", bbBrushColor);
|
|
rtSym("BrushAlpha%brush#alpha", bbBrushAlpha);
|
|
rtSym("BrushShininess%brush#shininess", bbBrushShininess);
|
|
rtSym("BrushTexture%brush%texture%frame=0%index=0", bbBrushTexture);
|
|
rtSym("%GetBrushTexture%brush%index=0", bbGetBrushTexture);
|
|
rtSym("BrushBlend%brush%blend", bbBrushBlend);
|
|
rtSym("BrushFX%brush%fx", bbBrushFX);
|
|
|
|
rtSym("%LoadMesh$file%parent=0", bbLoadMesh);
|
|
rtSym("%LoadAnimMesh$file%parent=0", bbLoadAnimMesh);
|
|
rtSym("%LoadAnimSeq%entity$file", bbLoadAnimSeq);
|
|
|
|
rtSym("%CreateMesh%parent=0", bbCreateMesh);
|
|
rtSym("%CreateCube%parent=0", bbCreateCube);
|
|
rtSym("%CreateSphere%segments=8%parent=0", bbCreateSphere);
|
|
rtSym("%CreateCylinder%segments=8%solid=1%parent=0", bbCreateCylinder);
|
|
rtSym("%CreateCone%segments=8%solid=1%parent=0", bbCreateCone);
|
|
rtSym("%CopyMesh%mesh%parent=0", bbCopyMesh);
|
|
rtSym("ScaleMesh%mesh#x_scale#y_scale#z_scale", bbScaleMesh);
|
|
rtSym("RotateMesh%mesh#pitch#yaw#roll", bbRotateMesh);
|
|
rtSym("PositionMesh%mesh#x#y#z", bbPositionMesh);
|
|
rtSym("FitMesh%mesh#x#y#z#width#height#depth%uniform=0", bbFitMesh);
|
|
rtSym("FlipMesh%mesh", bbFlipMesh);
|
|
rtSym("PaintMesh%mesh%brush", bbPaintMesh);
|
|
rtSym("AddMesh%source_mesh%dest_mesh", bbAddMesh);
|
|
rtSym("UpdateNormals%mesh", bbUpdateNormals);
|
|
rtSym("LightMesh%mesh#red#green#blue#range=0#x=0#y=0#z=0", bbLightMesh);
|
|
rtSym("#MeshWidth%mesh", bbMeshWidth);
|
|
rtSym("#MeshHeight%mesh", bbMeshHeight);
|
|
rtSym("#MeshDepth%mesh", bbMeshDepth);
|
|
rtSym("%MeshesIntersect%mesh_a%mesh_b", bbMeshesIntersect);
|
|
rtSym("%CountSurfaces%mesh", bbCountSurfaces);
|
|
rtSym("%GetSurface%mesh%surface_index", bbGetSurface);
|
|
rtSym("MeshCullBox%mesh#x#y#z#width#height#depth", bbMeshCullBox);
|
|
|
|
rtSym("%CreateSurface%mesh%brush=0", bbCreateSurface);
|
|
rtSym("%GetSurfaceBrush%surface", bbGetSurfaceBrush);
|
|
rtSym("%GetEntityBrush%entity", bbGetEntityBrush);
|
|
rtSym("%FindSurface%mesh%brush", bbFindSurface);
|
|
rtSym("ClearSurface%surface%clear_vertices=1%clear_triangles=1", bbClearSurface);
|
|
rtSym("PaintSurface%surface%brush", bbPaintSurface);
|
|
rtSym("%AddVertex%surface#x#y#z#u=0#v=0#w=1", bbAddVertex);
|
|
rtSym("%AddTriangle%surface%v0%v1%v2", bbAddTriangle);
|
|
rtSym("VertexCoords%surface%index#x#y#z", bbVertexCoords);
|
|
rtSym("VertexNormal%surface%index#nx#ny#nz", bbVertexNormal);
|
|
rtSym("VertexColor%surface%index#red#green#blue#alpha=1", bbVertexColor);
|
|
rtSym("VertexTexCoords%surface%index#u#v#w=1%coord_set=0", bbVertexTexCoords);
|
|
rtSym("%CountVertices%surface", bbCountVertices);
|
|
rtSym("%CountTriangles%surface", bbCountTriangles);
|
|
rtSym("#VertexX%surface%index", bbVertexX);
|
|
rtSym("#VertexY%surface%index", bbVertexY);
|
|
rtSym("#VertexZ%surface%index", bbVertexZ);
|
|
rtSym("#VertexNX%surface%index", bbVertexNX);
|
|
rtSym("#VertexNY%surface%index", bbVertexNY);
|
|
rtSym("#VertexNZ%surface%index", bbVertexNZ);
|
|
rtSym("#VertexRed%surface%index", bbVertexRed);
|
|
rtSym("#VertexGreen%surface%index", bbVertexGreen);
|
|
rtSym("#VertexBlue%surface%index", bbVertexBlue);
|
|
rtSym("#VertexAlpha%surface%index", bbVertexAlpha);
|
|
rtSym("#VertexU%surface%index%coord_set=0", bbVertexU);
|
|
rtSym("#VertexV%surface%index%coord_set=0", bbVertexV);
|
|
rtSym("#VertexW%surface%index%coord_set=0", bbVertexW);
|
|
rtSym("%TriangleVertex%surface%index%vertex", bbTriangleVertex);
|
|
|
|
rtSym("%CreateCamera%parent=0", bbCreateCamera);
|
|
rtSym("CameraZoom%camera#zoom", bbCameraZoom);
|
|
rtSym("CameraRange%camera#near#far", bbCameraRange);
|
|
rtSym("CameraClsColor%camera#red#green#blue", bbCameraClsColor);
|
|
rtSym("CameraClsMode%camera%cls_color%cls_zbuffer", bbCameraClsMode);
|
|
rtSym("CameraProjMode%camera%mode", bbCameraProjMode);
|
|
rtSym("CameraViewport%camera%x%y%width%height", bbCameraViewport);
|
|
rtSym("CameraFogColor%camera#red#green#blue", bbCameraFogColor);
|
|
rtSym("CameraFogRange%camera#near#far", bbCameraFogRange);
|
|
rtSym("CameraFogMode%camera%mode", bbCameraFogMode);
|
|
rtSym("CameraProject%camera#x#y#z", bbCameraProject);
|
|
rtSym("#ProjectedX", bbProjectedX);
|
|
rtSym("#ProjectedY", bbProjectedY);
|
|
rtSym("#ProjectedZ", bbProjectedZ);
|
|
|
|
rtSym("%EntityInView%entity%camera", bbEntityInView);
|
|
rtSym("%EntityVisible%src_entity%dest_entity", bbEntityVisible);
|
|
|
|
rtSym("%EntityPick%entity#range", bbEntityPick);
|
|
rtSym("%LinePick#x#y#z#dx#dy#dz#radius=0", bbLinePick);
|
|
rtSym("%CameraPick%camera#viewport_x#viewport_y", bbCameraPick);
|
|
|
|
rtSym("#PickedX", bbPickedX);
|
|
rtSym("#PickedY", bbPickedY);
|
|
rtSym("#PickedZ", bbPickedZ);
|
|
rtSym("#PickedNX", bbPickedNX);
|
|
rtSym("#PickedNY", bbPickedNY);
|
|
rtSym("#PickedNZ", bbPickedNZ);
|
|
rtSym("#PickedTime", bbPickedTime);
|
|
rtSym("%PickedEntity", bbPickedEntity);
|
|
rtSym("%PickedSurface", bbPickedSurface);
|
|
rtSym("%PickedTriangle", bbPickedTriangle);
|
|
|
|
rtSym("%CreateLight%type=1%parent=0", bbCreateLight);
|
|
rtSym("LightColor%light#red#green#blue", bbLightColor);
|
|
rtSym("LightRange%light#range", bbLightRange);
|
|
rtSym("LightConeAngles%light#inner_angle#outer_angle", bbLightConeAngles);
|
|
|
|
rtSym("%CreatePivot%parent=0", bbCreatePivot);
|
|
|
|
rtSym("%CreateSprite%parent=0", bbCreateSprite);
|
|
rtSym("%LoadSprite$file%texture_flags=1%parent=0", bbLoadSprite);
|
|
rtSym("RotateSprite%sprite#angle", bbRotateSprite);
|
|
rtSym("ScaleSprite%sprite#x_scale#y_scale", bbScaleSprite);
|
|
rtSym("HandleSprite%sprite#x_handle#y_handle", bbHandleSprite);
|
|
rtSym("SpriteViewMode%sprite%view_mode", bbSpriteViewMode);
|
|
|
|
rtSym("%LoadMD2$file%parent=0", bbLoadMD2);
|
|
rtSym("AnimateMD2%md2%mode=1#speed=1%first_frame=0%last_frame=9999#transition=0", bbAnimateMD2);
|
|
rtSym("#MD2AnimTime%md2", bbMD2AnimTime);
|
|
rtSym("%MD2AnimLength%md2", bbMD2AnimLength);
|
|
rtSym("%MD2Animating%md2", bbMD2Animating);
|
|
|
|
rtSym("%LoadBSP$file#gamma_adj=0%parent=0", bbLoadBSP);
|
|
rtSym("BSPLighting%bsp%use_lightmaps", bbBSPLighting);
|
|
rtSym("BSPAmbientLight%bsp#red#green#blue", bbBSPAmbientLight);
|
|
|
|
rtSym("%CreateMirror%parent=0", bbCreateMirror);
|
|
|
|
rtSym("%CreatePlane%segments=1%parent=0", bbCreatePlane);
|
|
|
|
rtSym("%CreateTerrain%grid_size%parent=0", bbCreateTerrain);
|
|
rtSym("%LoadTerrain$heightmap_file%parent=0", bbLoadTerrain);
|
|
rtSym("TerrainDetail%terrain%detail_level%morph=0", bbTerrainDetail);
|
|
rtSym("TerrainShading%terrain%enable", bbTerrainShading);
|
|
rtSym("#TerrainX%terrain#world_x#world_y#world_z", bbTerrainX);
|
|
rtSym("#TerrainY%terrain#world_x#world_y#world_z", bbTerrainY);
|
|
rtSym("#TerrainZ%terrain#world_x#world_y#world_z", bbTerrainZ);
|
|
rtSym("%TerrainSize%terrain", bbTerrainSize);
|
|
rtSym("#TerrainHeight%terrain%terrain_x%terrain_z", bbTerrainHeight);
|
|
rtSym("ModifyTerrain%terrain%terrain_x%terrain_z#height%realtime=0", bbModifyTerrain);
|
|
|
|
rtSym("%CreateListener%parent#rolloff_factor=1#doppler_scale=1#distance_scale=1", bbCreateListener);
|
|
rtSym("%EmitSound%sound%entity", bbEmitSound);
|
|
|
|
rtSym("%CopyEntity%entity%parent=0", bbCopyEntity);
|
|
|
|
rtSym("#EntityX%entity%global=0", bbEntityX);
|
|
rtSym("#EntityY%entity%global=0", bbEntityY);
|
|
rtSym("#EntityZ%entity%global=0", bbEntityZ);
|
|
rtSym("#EntityPitch%entity%global=0", bbEntityPitch);
|
|
rtSym("#EntityYaw%entity%global=0", bbEntityYaw);
|
|
rtSym("#EntityRoll%entity%global=0", bbEntityRoll);
|
|
rtSym("#GetMatElement%entity%row%column", bbGetMatElement);
|
|
rtSym("TFormPoint#x#y#z%source_entity%dest_entity", bbTFormPoint);
|
|
rtSym("TFormVector#x#y#z%source_entity%dest_entity", bbTFormVector);
|
|
rtSym("TFormNormal#x#y#z%source_entity%dest_entity", bbTFormNormal);
|
|
rtSym("#TFormedX", bbTFormedX);
|
|
rtSym("#TFormedY", bbTFormedY);
|
|
rtSym("#TFormedZ", bbTFormedZ);
|
|
rtSym("#VectorYaw#x#y#z", bbVectorYaw);
|
|
rtSym("#VectorPitch#x#y#z", bbVectorPitch);
|
|
rtSym("#DeltaPitch%src_entity%dest_entity", bbDeltaPitch);
|
|
rtSym("#DeltaYaw%src_entity%dest_entity", bbDeltaYaw);
|
|
|
|
rtSym("ResetEntity%entity", bbResetEntity);
|
|
rtSym("EntityType%entity%collision_type%recursive=0", bbEntityType);
|
|
rtSym("EntityPickMode%entity%pick_geometry%obscurer=1", bbEntityPickMode);
|
|
rtSym("%GetParent%entity", bbGetParent);
|
|
rtSym("%GetEntityType%entity", bbGetEntityType);
|
|
rtSym("EntityRadius%entity#x_radius#y_radius=0", bbEntityRadius);
|
|
rtSym("EntityBox%entity#x#y#z#width#height#depth", bbEntityBox);
|
|
rtSym("#EntityDistance%source_entity%destination_entity", bbEntityDistance);
|
|
rtSym("%EntityCollided%entity%type", bbEntityCollided);
|
|
|
|
rtSym("%CountCollisions%entity", bbCountCollisions);
|
|
rtSym("#CollisionX%entity%collision_index", bbCollisionX);
|
|
rtSym("#CollisionY%entity%collision_index", bbCollisionY);
|
|
rtSym("#CollisionZ%entity%collision_index", bbCollisionZ);
|
|
rtSym("#CollisionNX%entity%collision_index", bbCollisionNX);
|
|
rtSym("#CollisionNY%entity%collision_index", bbCollisionNY);
|
|
rtSym("#CollisionNZ%entity%collision_index", bbCollisionNZ);
|
|
rtSym("#CollisionTime%entity%collision_index", bbCollisionTime);
|
|
rtSym("%CollisionEntity%entity%collision_index", bbCollisionEntity);
|
|
rtSym("%CollisionSurface%entity%collision_index", bbCollisionSurface);
|
|
rtSym("%CollisionTriangle%entity%collision_index", bbCollisionTriangle);
|
|
|
|
rtSym("MoveEntity%entity#x#y#z", bbMoveEntity);
|
|
rtSym("TurnEntity%entity#pitch#yaw#roll%global=0", bbTurnEntity);
|
|
rtSym("TranslateEntity%entity#x#y#z%global=0", bbTranslateEntity);
|
|
rtSym("PositionEntity%entity#x#y#z%global=0", bbPositionEntity);
|
|
rtSym("ScaleEntity%entity#x_scale#y_scale#z_scale%global=0", bbScaleEntity);
|
|
rtSym("RotateEntity%entity#pitch#yaw#roll%global=0", bbRotateEntity);
|
|
rtSym("PointEntity%entity%target#roll=0", bbPointEntity);
|
|
rtSym("AlignToVector%entity#vector_x#vector_y#vector_z%axis#rate=1", bbAlignToVector);
|
|
rtSym("SetAnimTime%entity#time%anim_seq=0", bbSetAnimTime);
|
|
rtSym("Animate%entity%mode=1#speed=1%sequence=0#transition=0", bbAnimate);
|
|
rtSym("SetAnimKey%entity%frame%pos_key=1%rot_key=1%scale_key=1", bbSetAnimKey);
|
|
rtSym("%AddAnimSeq%entity%length", bbAddAnimSeq);
|
|
rtSym("%ExtractAnimSeq%entity%first_frame%last_frame%anim_seq=0", bbExtractAnimSeq);
|
|
rtSym("%AnimSeq%entity", bbAnimSeq);
|
|
rtSym("#AnimTime%entity", bbAnimTime);
|
|
rtSym("%AnimLength%entity", bbAnimLength);
|
|
rtSym("%Animating%entity", bbAnimating);
|
|
|
|
rtSym("EntityParent%entity%parent%global=1", bbEntityParent);
|
|
rtSym("%CountChildren%entity", bbCountChildren);
|
|
rtSym("%GetChild%entity%index", bbGetChild);
|
|
rtSym("%FindChild%entity$name", bbFindChild);
|
|
|
|
rtSym("PaintEntity%entity%brush", bbPaintEntity);
|
|
rtSym("EntityColor%entity#red#green#blue", bbEntityColor);
|
|
rtSym("EntityAlpha%entity#alpha", bbEntityAlpha);
|
|
rtSym("EntityShininess%entity#shininess", bbEntityShininess);
|
|
rtSym("EntityTexture%entity%texture%frame=0%index=0", bbEntityTexture);
|
|
rtSym("EntityBlend%entity%blend", bbEntityBlend);
|
|
rtSym("EntityFX%entity%fx", bbEntityFX);
|
|
rtSym("EntityAutoFade%entity#near#far", bbEntityAutoFade);
|
|
rtSym("EntityOrder%entity%order", bbEntityOrder);
|
|
rtSym("HideEntity%entity", bbHideEntity);
|
|
rtSym("ShowEntity%entity", bbShowEntity);
|
|
rtSym("FreeEntity%entity", bbFreeEntity);
|
|
|
|
rtSym("NameEntity%entity$name", bbNameEntity);
|
|
rtSym("$EntityName%entity", bbEntityName);
|
|
rtSym("$EntityClass%entity", bbEntityClass);
|
|
} |