mirror of
https://github.com/aap/librw.git
synced 2024-11-25 05:05:42 +00:00
started implementing tristrip; implemented camera frustum
This commit is contained in:
parent
c2780d56e9
commit
4941711964
36
Makefile
36
Makefile
@ -1,33 +1,11 @@
|
|||||||
# null, opengl
|
# null, gl3, ps2, d3d9
|
||||||
BUILD=null
|
BUILD := null
|
||||||
|
TARGET := librw-$(BUILD).a
|
||||||
# e.g. null -> -DRW_NULL
|
CFLAGS := -Wall -Wextra -g -fno-diagnostics-show-caret \
|
||||||
BUILDDEF:=$(shell echo $(BUILD) | tr a-z A-Z | sed 's/^/-DRW_/')
|
|
||||||
BUILDDIR=build-$(BUILD)
|
|
||||||
SRCDIR=src
|
|
||||||
#SRC := $(patsubst %.cpp,$(SRCDIR)/%.cpp, $(wildcard *.cpp))
|
|
||||||
SRC := $(wildcard $(SRCDIR)/*.cpp $(SRCDIR)/*/*.cpp)
|
|
||||||
OBJ := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.o,$(SRC))
|
|
||||||
DEP := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.d,$(SRC))
|
|
||||||
INC := -I/usr/local/include
|
|
||||||
CFLAGS=-Wall -Wextra -g $(BUILDDEF) -fno-diagnostics-show-caret \
|
|
||||||
-Wno-parentheses -Wno-invalid-offsetof \
|
-Wno-parentheses -Wno-invalid-offsetof \
|
||||||
-Wno-unused-parameter -Wno-sign-compare
|
-Wno-unused-parameter -Wno-sign-compare
|
||||||
LIB=librw-$(BUILD).a
|
|
||||||
|
|
||||||
$(LIB): $(OBJ)
|
include Make.common
|
||||||
|
|
||||||
|
$(TARGET): $(OBJ)
|
||||||
ar scr $@ $(OBJ)
|
ar scr $@ $(OBJ)
|
||||||
|
|
||||||
$(BUILDDIR)/%.o: $(SRCDIR)/%.cpp
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(CXX) $(CFLAGS) $(INC) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILDDIR)/%.d: $(SRCDIR)/%.cpp
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(CXX) -MM -MT '$(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.o,$<)' $(CFLAGS) $(INC) $< > $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
echo $(SRC)
|
|
||||||
rm -rf $(BUILDDIR)/*
|
|
||||||
|
|
||||||
-include $(DEP)
|
|
||||||
|
93
src/base.cpp
93
src/base.cpp
@ -184,9 +184,9 @@ V3d
|
|||||||
Matrix::transPoint(const V3d &p)
|
Matrix::transPoint(const V3d &p)
|
||||||
{
|
{
|
||||||
V3d res = this->pos;
|
V3d res = this->pos;
|
||||||
res = add(res, scale(this->right, p.x));
|
res = add(res, rw::scale(this->right, p.x));
|
||||||
res = add(res, scale(this->up, p.y));
|
res = add(res, rw::scale(this->up, p.y));
|
||||||
res = add(res, scale(this->at, p.z));
|
res = add(res, rw::scale(this->at, p.z));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,9 +194,9 @@ V3d
|
|||||||
Matrix::transVec(const V3d &v)
|
Matrix::transVec(const V3d &v)
|
||||||
{
|
{
|
||||||
V3d res;
|
V3d res;
|
||||||
res = scale(this->right, v.x);
|
res = rw::scale(this->right, v.x);
|
||||||
res = add(res, scale(this->up, v.y));
|
res = add(res, rw::scale(this->up, v.y));
|
||||||
res = add(res, scale(this->at, v.z));
|
res = add(res, rw::scale(this->at, v.z));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +251,87 @@ Matrix::transpose(Matrix *m1, Matrix *m2)
|
|||||||
matrixTranspose((float32*)m1, (float32*)m2);
|
matrixTranspose((float32*)m1, (float32*)m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Matrix::rotate(V3d *axis, float32 angle, CombineOp op)
|
||||||
|
{
|
||||||
|
Matrix tmp;
|
||||||
|
V3d v = normalize(*axis);
|
||||||
|
angle = angle*M_PI/180.0f;
|
||||||
|
float32 s = sin(angle);
|
||||||
|
float32 c = cos(angle);
|
||||||
|
float32 t = 1.0f - cos(angle);
|
||||||
|
|
||||||
|
Matrix rot = identMat;
|
||||||
|
rot.right.x = c + v.x*v.x*t;
|
||||||
|
rot.right.y = v.x*v.y*t + v.z*s;
|
||||||
|
rot.right.z = v.z*v.x*t - v.y*s;
|
||||||
|
rot.up.x = v.x*v.y*t - v.z*s;
|
||||||
|
rot.up.y = c + v.y*v.y*t;
|
||||||
|
rot.up.z = v.y*v.z*t + v.x*s;
|
||||||
|
rot.at.x = v.z*v.x*t + v.y*s;
|
||||||
|
rot.at.y = v.y*v.z*t - v.x*s;
|
||||||
|
rot.at.z = c + v.z*v.z*t;
|
||||||
|
|
||||||
|
switch(op){
|
||||||
|
case COMBINEREPLACE:
|
||||||
|
*this = rot;
|
||||||
|
break;
|
||||||
|
case COMBINEPRECONCAT:
|
||||||
|
mult(&tmp, this, &rot);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
case COMBINEPOSTCONCAT:
|
||||||
|
mult(&tmp, &rot, this);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Matrix::translate(V3d *translation, CombineOp op)
|
||||||
|
{
|
||||||
|
Matrix tmp;
|
||||||
|
Matrix trans = identMat;
|
||||||
|
trans.pos = *translation;
|
||||||
|
switch(op){
|
||||||
|
case COMBINEREPLACE:
|
||||||
|
*this = trans;
|
||||||
|
break;
|
||||||
|
case COMBINEPRECONCAT:
|
||||||
|
mult(&tmp, this, &trans);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
case COMBINEPOSTCONCAT:
|
||||||
|
mult(&tmp, &trans, this);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Matrix::scale(V3d *scale, CombineOp op)
|
||||||
|
{
|
||||||
|
Matrix tmp;
|
||||||
|
Matrix scl = identMat;
|
||||||
|
scl.right.x = scale->x;
|
||||||
|
scl.right.y = scale->y;
|
||||||
|
scl.right.z = scale->z;
|
||||||
|
switch(op){
|
||||||
|
case COMBINEREPLACE:
|
||||||
|
*this = scl;
|
||||||
|
break;
|
||||||
|
case COMBINEPRECONCAT:
|
||||||
|
mult(&tmp, this, &scl);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
case COMBINEPOSTCONCAT:
|
||||||
|
mult(&tmp, &scl, this);
|
||||||
|
*this = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Matrix3
|
Matrix3
|
||||||
Matrix3::makeRotation(const Quat &q)
|
Matrix3::makeRotation(const Quat &q)
|
||||||
|
136
src/camera.cpp
136
src/camera.cpp
@ -26,6 +26,136 @@ defaultEndUpdateCB(Camera *cam)
|
|||||||
engine->endUpdate(cam);
|
engine->endUpdate(cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buildPlanes(Camera *cam)
|
||||||
|
{
|
||||||
|
V3d *c = cam->frustumCorners;
|
||||||
|
FrustumPlane *p = cam->frustumPlanes;
|
||||||
|
V3d v51 = sub(c[1], c[5]);
|
||||||
|
V3d v73 = sub(c[3], c[7]);
|
||||||
|
|
||||||
|
/* Far plane */
|
||||||
|
p[0].plane.normal = cam->getFrame()->getLTM()->at;
|
||||||
|
p[0].plane.distance = dot(p[0].plane.normal, c[4]);
|
||||||
|
p[0].closestX = p[0].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[0].closestY = p[0].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[0].closestZ = p[0].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
|
||||||
|
/* Near plane */
|
||||||
|
p[1].plane.normal = neg(p[0].plane.normal);
|
||||||
|
p[1].plane.distance = dot(p[1].plane.normal, c[0]);
|
||||||
|
p[1].closestX = p[1].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[1].closestY = p[1].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[1].closestZ = p[1].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
|
||||||
|
/* Right plane */
|
||||||
|
p[2].plane.normal = normalize(cross(v51,
|
||||||
|
sub(c[6], c[5])));
|
||||||
|
p[2].plane.distance = dot(p[2].plane.normal, c[1]);
|
||||||
|
p[2].closestX = p[2].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[2].closestY = p[2].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[2].closestZ = p[2].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
|
||||||
|
/* Top plane */
|
||||||
|
p[3].plane.normal = normalize(cross(sub(c[4], c[5]),
|
||||||
|
v51));
|
||||||
|
p[3].plane.distance = dot(p[3].plane.normal, c[1]);
|
||||||
|
p[3].closestX = p[3].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[3].closestY = p[3].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[3].closestZ = p[3].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
|
||||||
|
/* Left plane */
|
||||||
|
p[4].plane.normal = normalize(cross(v73,
|
||||||
|
sub(c[4], c[7])));
|
||||||
|
p[4].plane.distance = dot(p[4].plane.normal, c[3]);
|
||||||
|
p[4].closestX = p[4].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[4].closestY = p[4].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[4].closestZ = p[4].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
|
||||||
|
/* Bottom plane */
|
||||||
|
p[5].plane.normal = normalize(cross(sub(c[6], c[7]),
|
||||||
|
v73));
|
||||||
|
p[5].plane.distance = dot(p[5].plane.normal, c[3]);
|
||||||
|
p[5].closestX = p[5].plane.normal.x < 0.0f ? 0 : 1;
|
||||||
|
p[5].closestY = p[5].plane.normal.y < 0.0f ? 0 : 1;
|
||||||
|
p[5].closestZ = p[5].plane.normal.z < 0.0f ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buildClipPersp(Camera *cam)
|
||||||
|
{
|
||||||
|
Matrix *ltm = cam->getFrame()->getLTM();
|
||||||
|
|
||||||
|
/* First we calculate the 4 points on the view window. */
|
||||||
|
V3d up = scale(ltm->up, cam->viewWindow.y);
|
||||||
|
V3d left = scale(ltm->right, cam->viewWindow.x);
|
||||||
|
V3d *c = cam->frustumCorners;
|
||||||
|
c[0] = add(add(ltm->at, up), left); // top left
|
||||||
|
c[1] = sub(add(ltm->at, up), left); // top right
|
||||||
|
c[2] = sub(sub(ltm->at, up), left); // bottom right
|
||||||
|
c[3] = add(sub(ltm->at, up), left); // bottom left
|
||||||
|
|
||||||
|
/* Now Calculate near and far corners. */
|
||||||
|
V3d off = sub(scale(ltm->up, cam->viewOffset.y),
|
||||||
|
scale(ltm->right, cam->viewOffset.x));
|
||||||
|
for(int32 i = 0; i < 4; i++){
|
||||||
|
V3d corner = sub(cam->frustumCorners[i], off);
|
||||||
|
V3d pos = add(ltm->pos, off);
|
||||||
|
c[i] = add(scale(corner, cam->nearPlane), pos);
|
||||||
|
c[i+4] = add(scale(corner, cam->farPlane), pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildPlanes(cam);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buildClipParallel(Camera *cam)
|
||||||
|
{
|
||||||
|
Matrix *ltm = cam->getFrame()->getLTM();
|
||||||
|
float32 nearoffx = -(1.0f - cam->nearPlane)*cam->viewOffset.x;
|
||||||
|
float32 nearoffy = (1.0f - cam->nearPlane)*cam->viewOffset.y;
|
||||||
|
float32 faroffx = -(1.0f - cam->farPlane)*cam->viewOffset.x;
|
||||||
|
float32 faroffy = (1.0f - cam->farPlane)*cam->viewOffset.y;
|
||||||
|
|
||||||
|
V3d *c = cam->frustumCorners;
|
||||||
|
c[0].x = nearoffx + cam->viewWindow.x;
|
||||||
|
c[0].y = nearoffy + cam->viewWindow.y;
|
||||||
|
c[0].z = cam->nearPlane;
|
||||||
|
|
||||||
|
c[1].x = nearoffx - cam->viewWindow.x;
|
||||||
|
c[1].y = nearoffy + cam->viewWindow.y;
|
||||||
|
c[1].z = cam->nearPlane;
|
||||||
|
|
||||||
|
c[2].x = nearoffx - cam->viewWindow.x;
|
||||||
|
c[2].y = nearoffy - cam->viewWindow.y;
|
||||||
|
c[2].z = cam->nearPlane;
|
||||||
|
|
||||||
|
c[3].x = nearoffx + cam->viewWindow.x;
|
||||||
|
c[3].y = nearoffy - cam->viewWindow.y;
|
||||||
|
c[3].z = cam->nearPlane;
|
||||||
|
|
||||||
|
c[4].x = faroffx + cam->viewWindow.x;
|
||||||
|
c[4].y = faroffy + cam->viewWindow.y;
|
||||||
|
c[4].z = cam->farPlane;
|
||||||
|
|
||||||
|
c[5].x = faroffx - cam->viewWindow.x;
|
||||||
|
c[5].y = faroffy + cam->viewWindow.y;
|
||||||
|
c[5].z = cam->farPlane;
|
||||||
|
|
||||||
|
c[6].x = faroffx - cam->viewWindow.x;
|
||||||
|
c[6].y = faroffy - cam->viewWindow.y;
|
||||||
|
c[6].z = cam->farPlane;
|
||||||
|
|
||||||
|
c[7].x = faroffx + cam->viewWindow.x;
|
||||||
|
c[7].y = faroffy - cam->viewWindow.y;
|
||||||
|
c[7].z = cam->farPlane;
|
||||||
|
|
||||||
|
for(int32 i = 0; i < 8; i++)
|
||||||
|
c[i] = ltm->transPoint(c[i]);
|
||||||
|
|
||||||
|
buildPlanes(cam);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cameraSync(ObjectWithFrame *obj)
|
cameraSync(ObjectWithFrame *obj)
|
||||||
{
|
{
|
||||||
@ -85,6 +215,8 @@ cameraSync(ObjectWithFrame *obj)
|
|||||||
proj.at.y = -proj.pos.y + 0.5f;
|
proj.at.y = -proj.pos.y + 0.5f;
|
||||||
proj.at.z = 1.0f;
|
proj.at.z = 1.0f;
|
||||||
proj.atw = 1.0f;
|
proj.atw = 1.0f;
|
||||||
|
Matrix::mult(&cam->viewMatrix, &proj, &inv);
|
||||||
|
buildClipPersp(cam);
|
||||||
}else{
|
}else{
|
||||||
proj.at.x = cam->viewOffset.x*xscl;
|
proj.at.x = cam->viewOffset.x*xscl;
|
||||||
proj.at.y = -cam->viewOffset.y*yscl;
|
proj.at.y = -cam->viewOffset.y*yscl;
|
||||||
@ -95,8 +227,10 @@ cameraSync(ObjectWithFrame *obj)
|
|||||||
proj.pos.y = -proj.at.y + 0.5f;
|
proj.pos.y = -proj.at.y + 0.5f;
|
||||||
proj.pos.z = 0.0f;
|
proj.pos.z = 0.0f;
|
||||||
proj.posw = 1.0f;
|
proj.posw = 1.0f;
|
||||||
|
Matrix::mult(&cam->viewMatrix, &proj, &inv);
|
||||||
|
buildClipParallel(cam);
|
||||||
}
|
}
|
||||||
Matrix::mult(&cam->viewMatrix, &proj, &inv);
|
cam->frustumBoundBox.calculate(cam->frustumCorners, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -316,8 +316,10 @@ Clump::render(void)
|
|||||||
//
|
//
|
||||||
|
|
||||||
static void
|
static void
|
||||||
atomicSync(ObjectWithFrame*)
|
atomicSync(ObjectWithFrame *obj)
|
||||||
{
|
{
|
||||||
|
// TODO: interpolate
|
||||||
|
obj->object.privateFlags |= Atomic::WORLDBOUNDDIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -339,13 +341,17 @@ Atomic::create(void)
|
|||||||
atomic->object.object.init(Atomic::ID, 0);
|
atomic->object.object.init(Atomic::ID, 0);
|
||||||
atomic->object.syncCB = atomicSync;
|
atomic->object.syncCB = atomicSync;
|
||||||
atomic->geometry = nil;
|
atomic->geometry = nil;
|
||||||
|
atomic->boundingSphere.center.set(0.0f, 0.0f, 0.0f);
|
||||||
|
atomic->boundingSphere.radius = 0.0f;
|
||||||
atomic->worldBoundingSphere.center.set(0.0f, 0.0f, 0.0f);
|
atomic->worldBoundingSphere.center.set(0.0f, 0.0f, 0.0f);
|
||||||
atomic->worldBoundingSphere.radius = 0.0f;
|
atomic->worldBoundingSphere.radius = 0.0f;
|
||||||
atomic->setFrame(nil);
|
atomic->setFrame(nil);
|
||||||
|
atomic->object.object.privateFlags |= WORLDBOUNDDIRTY;
|
||||||
atomic->clump = nil;
|
atomic->clump = nil;
|
||||||
atomic->pipeline = nil;
|
atomic->pipeline = nil;
|
||||||
atomic->renderCB = Atomic::defaultRenderCB;
|
atomic->renderCB = Atomic::defaultRenderCB;
|
||||||
atomic->object.object.flags = Atomic::COLLISIONTEST | Atomic::RENDER;
|
atomic->object.object.flags = Atomic::COLLISIONTEST | Atomic::RENDER;
|
||||||
|
// TODO: interpolator
|
||||||
|
|
||||||
// World extension
|
// World extension
|
||||||
atomic->world = nil;
|
atomic->world = nil;
|
||||||
@ -363,9 +369,9 @@ Atomic::clone()
|
|||||||
if(atomic == nil)
|
if(atomic == nil)
|
||||||
return nil;
|
return nil;
|
||||||
atomic->object.object.copy(&this->object.object);
|
atomic->object.object.copy(&this->object.object);
|
||||||
atomic->object.object.privateFlags |= 1;
|
atomic->object.object.privateFlags |= WORLDBOUNDDIRTY;
|
||||||
if(this->geometry)
|
if(this->geometry)
|
||||||
atomic->setGeometry(this->geometry);
|
atomic->setGeometry(this->geometry, 0);
|
||||||
atomic->pipeline = this->pipeline;
|
atomic->pipeline = this->pipeline;
|
||||||
s_plglist.copy(atomic, this);
|
s_plglist.copy(atomic, this);
|
||||||
return atomic;
|
return atomic;
|
||||||
@ -393,28 +399,34 @@ Atomic::removeFromClump(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Atomic::setGeometry(Geometry *geo)
|
Atomic::setGeometry(Geometry *geo, uint32 flags)
|
||||||
{
|
{
|
||||||
if(this->geometry)
|
if(this->geometry)
|
||||||
this->geometry->destroy();
|
this->geometry->destroy();
|
||||||
if(geo)
|
if(geo)
|
||||||
geo->refCount++;
|
geo->refCount++;
|
||||||
this->geometry = geo;
|
this->geometry = geo;
|
||||||
// TODO: bounding stuff
|
if(flags & SAMEBOUNDINGSPHERE)
|
||||||
|
return;
|
||||||
|
if(geo){
|
||||||
|
this->boundingSphere = geo->morphTargets[0].boundingSphere;
|
||||||
|
if(this->getFrame()) // TODO: && getWorld???
|
||||||
|
this->getFrame()->updateObjects();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sphere*
|
Sphere*
|
||||||
Atomic::getWorldBoundingSphere(void)
|
Atomic::getWorldBoundingSphere(void)
|
||||||
{
|
{
|
||||||
Sphere *s = &this->worldBoundingSphere;
|
Sphere *s = &this->worldBoundingSphere;
|
||||||
|
// TODO: if we ever support morphing, check interpolation
|
||||||
if(!this->getFrame()->dirty() &&
|
if(!this->getFrame()->dirty() &&
|
||||||
(this->object.object.privateFlags & WORLDBOUNDDIRTY) == 0)
|
(this->object.object.privateFlags & WORLDBOUNDDIRTY) == 0)
|
||||||
return s;
|
return s;
|
||||||
Matrix *ltm = this->getFrame()->getLTM();
|
Matrix *ltm = this->getFrame()->getLTM();
|
||||||
// TODO: support scaling
|
// TODO: support scaling
|
||||||
// TODO: if we ever support morphing, fix this:
|
s->center = ltm->transPoint(this->boundingSphere.center);
|
||||||
s->center = ltm->transPoint(this->geometry->morphTargets[0].boundingSphere.center);
|
s->radius = this->boundingSphere.radius;
|
||||||
s->radius = this->geometry->morphTargets[0].boundingSphere.radius;
|
|
||||||
this->object.object.privateFlags &= ~WORLDBOUNDDIRTY;
|
this->object.object.privateFlags &= ~WORLDBOUNDDIRTY;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -445,10 +457,10 @@ Atomic::streamReadClump(Stream *stream,
|
|||||||
g = Geometry::streamRead(stream);
|
g = Geometry::streamRead(stream);
|
||||||
if(g == nil)
|
if(g == nil)
|
||||||
goto fail;
|
goto fail;
|
||||||
atomic->setGeometry(g);
|
atomic->setGeometry(g, 0);
|
||||||
g->destroy();
|
g->destroy();
|
||||||
}else
|
}else
|
||||||
atomic->setGeometry(geometryList[buf[1]]);
|
atomic->setGeometry(geometryList[buf[1]], 0);
|
||||||
atomic->object.object.flags = buf[2];
|
atomic->object.object.flags = buf[2];
|
||||||
|
|
||||||
atomicRights[0] = 0;
|
atomicRights[0] = 0;
|
||||||
|
@ -248,6 +248,27 @@ Frame::syncDirty(void)
|
|||||||
Frame::dirtyList.init();
|
Frame::dirtyList.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Frame::rotate(V3d *axis, float32 angle, CombineOp op)
|
||||||
|
{
|
||||||
|
this->matrix.rotate(axis, angle, op);
|
||||||
|
updateObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Frame::translate(V3d *trans, CombineOp op)
|
||||||
|
{
|
||||||
|
this->matrix.translate(trans, op);
|
||||||
|
updateObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Frame::scale(V3d *scl, CombineOp op)
|
||||||
|
{
|
||||||
|
this->matrix.scale(scl, op);
|
||||||
|
updateObjects();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Frame::updateObjects(void)
|
Frame::updateObjects(void)
|
||||||
{
|
{
|
||||||
|
@ -431,9 +431,26 @@ Geometry::generateTriangles(int8 *adc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dumpMesh(Mesh *m)
|
||||||
|
{
|
||||||
|
for(int32 i = 0; i < m->numIndices-2; i++)
|
||||||
|
// if(i % 2)
|
||||||
|
// printf("%3d %3d %3d\n",
|
||||||
|
// m->indices[i+1],
|
||||||
|
// m->indices[i],
|
||||||
|
// m->indices[i+2]);
|
||||||
|
// else
|
||||||
|
printf("%d %d %d\n",
|
||||||
|
m->indices[i],
|
||||||
|
m->indices[i+1],
|
||||||
|
m->indices[i+2]);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Geometry::buildMeshes(void)
|
Geometry::buildMeshes(void)
|
||||||
{
|
{
|
||||||
|
//dumpMesh(this->meshHeader->mesh);
|
||||||
delete this->meshHeader;
|
delete this->meshHeader;
|
||||||
|
|
||||||
Triangle *tri;
|
Triangle *tri;
|
||||||
@ -467,9 +484,8 @@ Geometry::buildMeshes(void)
|
|||||||
h->mesh[tri->matId].numIndices = idx;
|
h->mesh[tri->matId].numIndices = idx;
|
||||||
tri++;
|
tri++;
|
||||||
}
|
}
|
||||||
}else{
|
}else
|
||||||
assert(0 && "can't tristrip\n");
|
this->buildTristrips();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The idea is that even in meshes where winding is not preserved
|
/* The idea is that even in meshes where winding is not preserved
|
||||||
@ -508,9 +524,11 @@ Geometry::correctTristripWinding(void)
|
|||||||
/* Entering strip now,
|
/* Entering strip now,
|
||||||
* make sure winding is correct */
|
* make sure winding is correct */
|
||||||
inStrip = 1;
|
inStrip = 1;
|
||||||
if(newmesh->numIndices % 2)
|
if(newmesh->numIndices % 2){
|
||||||
newmesh->indices[newmesh->numIndices++] =
|
newmesh->indices[newmesh->numIndices] =
|
||||||
newmesh->indices[newmesh->numIndices-1];
|
newmesh->indices[newmesh->numIndices-1];
|
||||||
|
newmesh->numIndices++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newmesh->indices[newmesh->numIndices++] = mesh->indices[j];
|
newmesh->indices[newmesh->numIndices++] = mesh->indices[j];
|
||||||
}
|
}
|
||||||
|
@ -200,8 +200,8 @@ matfxRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
|||||||
InstanceData *inst = header->inst;
|
InstanceData *inst = header->inst;
|
||||||
int32 n = header->numMeshes;
|
int32 n = header->numMeshes;
|
||||||
|
|
||||||
rw::setRenderState(ALPHATESTFUNC, 1);
|
// rw::setRenderState(ALPHATESTFUNC, 1);
|
||||||
rw::setRenderState(ALPHATESTREF, 50);
|
// rw::setRenderState(ALPHATESTREF, 50);
|
||||||
|
|
||||||
int32 fx;
|
int32 fx;
|
||||||
while(n--){
|
while(n--){
|
||||||
@ -460,8 +460,8 @@ skinRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
|||||||
InstanceData *inst = header->inst;
|
InstanceData *inst = header->inst;
|
||||||
int32 n = header->numMeshes;
|
int32 n = header->numMeshes;
|
||||||
|
|
||||||
rw::setRenderState(ALPHATESTFUNC, 1);
|
// rw::setRenderState(ALPHATESTFUNC, 1);
|
||||||
rw::setRenderState(ALPHATESTREF, 50);
|
// rw::setRenderState(ALPHATESTREF, 50);
|
||||||
|
|
||||||
skinShader->use();
|
skinShader->use();
|
||||||
|
|
||||||
|
@ -84,8 +84,8 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header)
|
|||||||
InstanceData *inst = header->inst;
|
InstanceData *inst = header->inst;
|
||||||
int32 n = header->numMeshes;
|
int32 n = header->numMeshes;
|
||||||
|
|
||||||
rw::setRenderState(ALPHATESTFUNC, 1);
|
// rw::setRenderState(ALPHATESTFUNC, 1);
|
||||||
rw::setRenderState(ALPHATESTREF, 50);
|
// rw::setRenderState(ALPHATESTREF, 50);
|
||||||
|
|
||||||
simpleShader->use();
|
simpleShader->use();
|
||||||
|
|
||||||
|
37
src/prim.cpp
Normal file
37
src/prim.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwengine.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
void
|
||||||
|
BBox::calculate(V3d *points, int32 n)
|
||||||
|
{
|
||||||
|
this->inf = points[0];
|
||||||
|
this->sup = points[0];
|
||||||
|
while(--n){
|
||||||
|
points++;
|
||||||
|
if(points->x < this->inf.x)
|
||||||
|
this->inf.x = points->x;
|
||||||
|
if(points->y < this->inf.y)
|
||||||
|
this->inf.x = points->y;
|
||||||
|
if(points->z < this->inf.z)
|
||||||
|
this->inf.x = points->z;
|
||||||
|
if(points->x > this->sup.x)
|
||||||
|
this->sup.x = points->x;
|
||||||
|
if(points->y > this->sup.y)
|
||||||
|
this->sup.x = points->y;
|
||||||
|
if(points->z > this->sup.z)
|
||||||
|
this->sup.x = points->z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
src/rwbase.h
26
src/rwbase.h
@ -89,6 +89,7 @@ struct V2d
|
|||||||
this->x = x; this->y = y; }
|
this->x = x; this->y = y; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline V2d neg(const V2d &a) { return V2d(-a.x, -a.y); }
|
||||||
inline V2d add(const V2d &a, const V2d &b) { return V2d(a.x+b.x, a.y+b.y); }
|
inline V2d add(const V2d &a, const V2d &b) { return V2d(a.x+b.x, a.y+b.y); }
|
||||||
inline V2d sub(const V2d &a, const V2d &b) { return V2d(a.x-b.x, a.y-b.y); }
|
inline V2d sub(const V2d &a, const V2d &b) { return V2d(a.x-b.x, a.y-b.y); }
|
||||||
inline V2d scale(const V2d &a, float32 r) { return V2d(a.x*r, a.y*r); }
|
inline V2d scale(const V2d &a, float32 r) { return V2d(a.x*r, a.y*r); }
|
||||||
@ -104,6 +105,7 @@ struct V3d
|
|||||||
this->x = x; this->y = y; this->z = z; }
|
this->x = x; this->y = y; this->z = z; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline V3d neg(const V3d &a) { return V3d(-a.x, -a.y, -a.z); }
|
||||||
inline V3d add(const V3d &a, const V3d &b) { return V3d(a.x+b.x, a.y+b.y, a.z+b.z); }
|
inline V3d add(const V3d &a, const V3d &b) { return V3d(a.x+b.x, a.y+b.y, a.z+b.z); }
|
||||||
inline V3d sub(const V3d &a, const V3d &b) { return V3d(a.x-b.x, a.y-b.y, a.z-b.z); }
|
inline V3d sub(const V3d &a, const V3d &b) { return V3d(a.x-b.x, a.y-b.y, a.z-b.z); }
|
||||||
inline V3d scale(const V3d &a, float32 r) { return V3d(a.x*r, a.y*r, a.z*r); }
|
inline V3d scale(const V3d &a, float32 r) { return V3d(a.x*r, a.y*r, a.z*r); }
|
||||||
@ -146,6 +148,12 @@ inline V3d rotate(const V3d &v, const Quat &q) { return mult(mult(q, Quat(v)), c
|
|||||||
Quat lerp(const Quat &q, const Quat &p, float32 r);
|
Quat lerp(const Quat &q, const Quat &p, float32 r);
|
||||||
Quat slerp(const Quat &q, const Quat &p, float32 a);
|
Quat slerp(const Quat &q, const Quat &p, float32 a);
|
||||||
|
|
||||||
|
enum CombineOp
|
||||||
|
{
|
||||||
|
COMBINEREPLACE,
|
||||||
|
COMBINEPRECONCAT,
|
||||||
|
COMBINEPOSTCONCAT,
|
||||||
|
};
|
||||||
|
|
||||||
struct Matrix
|
struct Matrix
|
||||||
{
|
{
|
||||||
@ -171,6 +179,10 @@ struct Matrix
|
|||||||
static bool32 invert(Matrix *m1, Matrix *m2);
|
static bool32 invert(Matrix *m1, Matrix *m2);
|
||||||
static void invertOrthonormal(Matrix *m1, Matrix *m2);
|
static void invertOrthonormal(Matrix *m1, Matrix *m2);
|
||||||
static void transpose(Matrix *m1, Matrix *m2);
|
static void transpose(Matrix *m1, Matrix *m2);
|
||||||
|
// some more RW like helpers
|
||||||
|
void rotate(V3d *axis, float32 angle, CombineOp op);
|
||||||
|
void translate(V3d *translation, CombineOp op);
|
||||||
|
void scale(V3d *scl, CombineOp op);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Matrix3
|
struct Matrix3
|
||||||
@ -204,6 +216,20 @@ struct Sphere
|
|||||||
float32 radius;
|
float32 radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Plane
|
||||||
|
{
|
||||||
|
V3d normal;
|
||||||
|
float32 distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BBox
|
||||||
|
{
|
||||||
|
V3d sup;
|
||||||
|
V3d inf;
|
||||||
|
|
||||||
|
void calculate(V3d *points, int32 n);
|
||||||
|
};
|
||||||
|
|
||||||
enum PrimitiveType
|
enum PrimitiveType
|
||||||
{
|
{
|
||||||
PRIMTYPENONE = 0,
|
PRIMTYPENONE = 0,
|
||||||
|
@ -123,6 +123,9 @@ struct Frame : PluginBase<Frame>
|
|||||||
bool32 dirty(void) {
|
bool32 dirty(void) {
|
||||||
return !!(this->root->object.privateFlags & HIERARCHYSYNC); }
|
return !!(this->root->object.privateFlags & HIERARCHYSYNC); }
|
||||||
Matrix *getLTM(void);
|
Matrix *getLTM(void);
|
||||||
|
void rotate(V3d *axis, float32 angle, CombineOp op);
|
||||||
|
void translate(V3d *trans, CombineOp op);
|
||||||
|
void scale(V3d *trans, CombineOp op);
|
||||||
void updateObjects(void);
|
void updateObjects(void);
|
||||||
|
|
||||||
|
|
||||||
@ -409,6 +412,7 @@ struct Geometry : PluginBase<Geometry>
|
|||||||
void allocateData(void);
|
void allocateData(void);
|
||||||
void generateTriangles(int8 *adc = nil);
|
void generateTriangles(int8 *adc = nil);
|
||||||
void buildMeshes(void);
|
void buildMeshes(void);
|
||||||
|
void buildTristrips(void);
|
||||||
void correctTristripWinding(void);
|
void correctTristripWinding(void);
|
||||||
void removeUnusedMaterials(void);
|
void removeUnusedMaterials(void);
|
||||||
|
|
||||||
@ -447,9 +451,13 @@ struct Atomic : PluginBase<Atomic>
|
|||||||
// private
|
// private
|
||||||
WORLDBOUNDDIRTY = 0x01
|
WORLDBOUNDDIRTY = 0x01
|
||||||
};
|
};
|
||||||
|
enum {
|
||||||
|
SAMEBOUNDINGSPHERE = 0x01, // for setGeometry
|
||||||
|
};
|
||||||
|
|
||||||
ObjectWithFrame object;
|
ObjectWithFrame object;
|
||||||
Geometry *geometry;
|
Geometry *geometry;
|
||||||
|
Sphere boundingSphere;
|
||||||
Sphere worldBoundingSphere;
|
Sphere worldBoundingSphere;
|
||||||
Clump *clump;
|
Clump *clump;
|
||||||
LLLink inClump;
|
LLLink inClump;
|
||||||
@ -470,7 +478,7 @@ struct Atomic : PluginBase<Atomic>
|
|||||||
static Atomic *fromClump(LLLink *lnk){
|
static Atomic *fromClump(LLLink *lnk){
|
||||||
return LLLinkGetData(lnk, Atomic, inClump); }
|
return LLLinkGetData(lnk, Atomic, inClump); }
|
||||||
void removeFromClump(void);
|
void removeFromClump(void);
|
||||||
void setGeometry(Geometry *geo);
|
void setGeometry(Geometry *geo, uint32 flags);
|
||||||
Sphere *getWorldBoundingSphere(void);
|
Sphere *getWorldBoundingSphere(void);
|
||||||
ObjPipeline *getPipeline(void);
|
ObjPipeline *getPipeline(void);
|
||||||
void render(void) { this->renderCB(this); }
|
void render(void) { this->renderCB(this); }
|
||||||
@ -518,6 +526,8 @@ struct Light : PluginBase<Light>
|
|||||||
float32 getAngle(void);
|
float32 getAngle(void);
|
||||||
void setColor(float32 r, float32 g, float32 b);
|
void setColor(float32 r, float32 g, float32 b);
|
||||||
int32 getType(void){ return this->object.object.subType; }
|
int32 getType(void){ return this->object.object.subType; }
|
||||||
|
void setFlags(uint32 flags) { this->object.object.flags = flags; }
|
||||||
|
uint32 getFlags(void) { return this->object.object.flags; }
|
||||||
static Light *streamRead(Stream *stream);
|
static Light *streamRead(Stream *stream);
|
||||||
bool streamWrite(Stream *stream);
|
bool streamWrite(Stream *stream);
|
||||||
uint32 streamGetSize(void);
|
uint32 streamGetSize(void);
|
||||||
@ -535,6 +545,17 @@ struct Light : PluginBase<Light>
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FrustumPlane
|
||||||
|
{
|
||||||
|
Plane plane;
|
||||||
|
/* Used for BBox tests:
|
||||||
|
* 0 = inf is closer to normal direction
|
||||||
|
* 1 = sup is closer to normal direction */
|
||||||
|
uint8 closestX;
|
||||||
|
uint8 closestY;
|
||||||
|
uint8 closestZ;
|
||||||
|
};
|
||||||
|
|
||||||
struct Camera : PluginBase<Camera>
|
struct Camera : PluginBase<Camera>
|
||||||
{
|
{
|
||||||
enum { ID = 4 };
|
enum { ID = 4 };
|
||||||
@ -553,6 +574,10 @@ struct Camera : PluginBase<Camera>
|
|||||||
Matrix viewMatrix;
|
Matrix viewMatrix;
|
||||||
float32 zScale, zShift;
|
float32 zScale, zShift;
|
||||||
|
|
||||||
|
FrustumPlane frustumPlanes[6];
|
||||||
|
V3d frustumCorners[8];
|
||||||
|
BBox frustumBoundBox;
|
||||||
|
|
||||||
// clump link handled by plugin in RW
|
// clump link handled by plugin in RW
|
||||||
Clump *clump;
|
Clump *clump;
|
||||||
LLLink inClump;
|
LLLink inClump;
|
||||||
|
452
src/tristrip.cpp
Normal file
452
src/tristrip.cpp
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 2
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
struct GraphEdge
|
||||||
|
{
|
||||||
|
int32 node; /* index of the connected node */
|
||||||
|
uint32 isConnected : 1; /* is connected to other node */
|
||||||
|
uint32 otherEdge : 2; /* edge number on connected node */
|
||||||
|
uint32 isStrip : 1; /* is strip edge */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StripNode
|
||||||
|
{
|
||||||
|
uint16 v[3]; /* vertex indices */
|
||||||
|
uint8 parent : 2; /* tunnel parent node (edge index) */
|
||||||
|
uint8 visited : 1; /* visited in breadth first search */
|
||||||
|
uint8 stripVisited : 1; /* strip starting at this node was visited during search */
|
||||||
|
uint8 isEnd : 1; /* is in end list */
|
||||||
|
GraphEdge e[3];
|
||||||
|
int32 stripId; /* index of start node */
|
||||||
|
// int asdf;
|
||||||
|
LLLink inlist;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StripMesh
|
||||||
|
{
|
||||||
|
int32 numNodes;
|
||||||
|
StripNode *nodes;
|
||||||
|
LinkList loneNodes; /* nodes not connected to any others */
|
||||||
|
LinkList endNodes; /* strip start/end nodes */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
printNode(StripMesh *sm, StripNode *n)
|
||||||
|
{
|
||||||
|
printf("%3ld: %3d %3d.%d %3d.%d %3d.%d || %3d %3d %3d\n",
|
||||||
|
n - sm->nodes,
|
||||||
|
n->stripId,
|
||||||
|
n->e[0].node,
|
||||||
|
n->e[0].isStrip,
|
||||||
|
n->e[1].node,
|
||||||
|
n->e[1].isStrip,
|
||||||
|
n->e[2].node,
|
||||||
|
n->e[2].isStrip,
|
||||||
|
n->v[0],
|
||||||
|
n->v[1],
|
||||||
|
n->v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printLone(StripMesh *sm)
|
||||||
|
{
|
||||||
|
FORLIST(lnk, sm->loneNodes)
|
||||||
|
printNode(sm, LLLinkGetData(lnk, StripNode, inlist));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printEnds(StripMesh *sm)
|
||||||
|
{
|
||||||
|
FORLIST(lnk, sm->endNodes)
|
||||||
|
printNode(sm, LLLinkGetData(lnk, StripNode, inlist));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printSmesh(StripMesh *sm)
|
||||||
|
{
|
||||||
|
for(int32 i = 0; i < sm->numNodes; i++)
|
||||||
|
printNode(sm, &sm->nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collectFaces(Geometry *geo, StripMesh *sm, uint16 m)
|
||||||
|
{
|
||||||
|
StripNode *n;
|
||||||
|
Triangle *t;
|
||||||
|
sm->numNodes = 0;
|
||||||
|
for(int32 i = 0; i < geo->numTriangles; i++){
|
||||||
|
t = &geo->triangles[i];
|
||||||
|
if(t->matId == m){
|
||||||
|
n = &sm->nodes[sm->numNodes++];
|
||||||
|
n->v[0] = t->v[0];
|
||||||
|
n->v[1] = t->v[1];
|
||||||
|
n->v[2] = t->v[2];
|
||||||
|
n->e[0].node = 0;
|
||||||
|
n->e[1].node = 0;
|
||||||
|
n->e[2].node = 0;
|
||||||
|
n->e[0].isConnected = 0;
|
||||||
|
n->e[1].isConnected = 0;
|
||||||
|
n->e[2].isConnected = 0;
|
||||||
|
n->e[0].isStrip = 0;
|
||||||
|
n->e[1].isStrip = 0;
|
||||||
|
n->e[2].isStrip = 0;
|
||||||
|
n->parent = 0;
|
||||||
|
n->visited = 0;
|
||||||
|
n->stripVisited = 0;
|
||||||
|
n->isEnd = 0;
|
||||||
|
n->stripId = -1;
|
||||||
|
n->inlist.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find Triangle that has edge e. */
|
||||||
|
static GraphEdge
|
||||||
|
findEdge(StripMesh *sm, int32 e[2])
|
||||||
|
{
|
||||||
|
StripNode *n;
|
||||||
|
GraphEdge ge = { 0, 0, 0, 0 };
|
||||||
|
for(int32 i = 0; i < sm->numNodes; i++){
|
||||||
|
n = &sm->nodes[i];
|
||||||
|
for(int32 j = 0; j < 3; j++){
|
||||||
|
if(n->e[j].isConnected)
|
||||||
|
continue;
|
||||||
|
if(e[0] == n->v[j] &&
|
||||||
|
e[1] == n->v[(j+1) % 3]){
|
||||||
|
ge.node = i;
|
||||||
|
ge.isConnected = 1;
|
||||||
|
ge.otherEdge = j;
|
||||||
|
return ge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect nodes sharing an edge, preserving winding */
|
||||||
|
static void
|
||||||
|
connectNodes(StripMesh *sm)
|
||||||
|
{
|
||||||
|
StripNode *n, *nn;
|
||||||
|
int32 e[2];
|
||||||
|
GraphEdge ge;
|
||||||
|
for(int32 i = 0; i < sm->numNodes; i++){
|
||||||
|
n = &sm->nodes[i];
|
||||||
|
for(int32 j = 0; j < 3; j++){
|
||||||
|
if(n->e[j].isConnected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* flip edge and search for node */
|
||||||
|
e[1] = n->v[j];
|
||||||
|
e[0] = n->v[(j+1) % 3];
|
||||||
|
ge = findEdge(sm, e);
|
||||||
|
/* found node, now connect */
|
||||||
|
if(ge.isConnected){
|
||||||
|
n->e[j].node = ge.node;
|
||||||
|
n->e[j].isConnected = 1;
|
||||||
|
n->e[j].otherEdge = ge.otherEdge;
|
||||||
|
n->e[j].isStrip = 0;
|
||||||
|
nn = &sm->nodes[ge.node];
|
||||||
|
nn->e[ge.otherEdge].node = i;
|
||||||
|
nn->e[ge.otherEdge].isConnected = 1;
|
||||||
|
nn->e[ge.otherEdge].otherEdge = j;
|
||||||
|
nn->e[ge.otherEdge].isStrip = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
numConnections(StripNode *n)
|
||||||
|
{
|
||||||
|
return n->e[0].isConnected +
|
||||||
|
n->e[1].isConnected +
|
||||||
|
n->e[2].isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
numStripEdges(StripNode *n)
|
||||||
|
{
|
||||||
|
return n->e[0].isStrip +
|
||||||
|
n->e[1].isStrip +
|
||||||
|
n->e[2].isStrip;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IsEnd(n) (numConnections(n) > 0 && numStripEdges(n) < 2)
|
||||||
|
|
||||||
|
static void
|
||||||
|
complementEdge(StripMesh *sm, GraphEdge *e)
|
||||||
|
{
|
||||||
|
e->isStrip = !e->isStrip;
|
||||||
|
e = &sm->nodes[e->node].e[e->otherEdge];
|
||||||
|
e->isStrip = !e->isStrip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While possible extend a strip from a starting node until
|
||||||
|
* we find a node already in a strip. N.B. this function does
|
||||||
|
* make no attempts to connect to an already existing strip. */
|
||||||
|
static void
|
||||||
|
extendStrip(StripMesh *sm, StripNode *start)
|
||||||
|
{
|
||||||
|
StripNode *n, *nn;
|
||||||
|
n = start;
|
||||||
|
if(numConnections(n) == 0){
|
||||||
|
sm->loneNodes.append(&n->inlist);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sm->endNodes.append(&n->inlist);
|
||||||
|
n->isEnd = 1;
|
||||||
|
tail:
|
||||||
|
/* Find the next node to connect to on any of the three edges */
|
||||||
|
for(int32 i = 0; i < 3; i++){
|
||||||
|
if(!n->e[i].isConnected)
|
||||||
|
continue;
|
||||||
|
nn = &sm->nodes[n->e[i].node];
|
||||||
|
if(nn->stripId >= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* found one */
|
||||||
|
nn->stripId = n->stripId;
|
||||||
|
complementEdge(sm, &n->e[i]);
|
||||||
|
n = nn;
|
||||||
|
goto tail;
|
||||||
|
}
|
||||||
|
if(n != start){
|
||||||
|
sm->endNodes.append(&n->inlist);
|
||||||
|
n->isEnd = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buildStrips(StripMesh *sm)
|
||||||
|
{
|
||||||
|
StripNode *n;
|
||||||
|
for(int32 i = 0; i < sm->numNodes; i++){
|
||||||
|
n = &sm->nodes[i];
|
||||||
|
if(n->stripId >= 0)
|
||||||
|
continue;
|
||||||
|
n->stripId = i;
|
||||||
|
extendStrip(sm, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static StripNode*
|
||||||
|
findTunnel(StripMesh *sm, StripNode *n)
|
||||||
|
{
|
||||||
|
LinkList searchNodes;
|
||||||
|
StripNode *nn;
|
||||||
|
int edgetype;
|
||||||
|
int isEnd;
|
||||||
|
|
||||||
|
searchNodes.init();
|
||||||
|
edgetype = 0;
|
||||||
|
for(;;){
|
||||||
|
for(int32 i = 0; i < 3; i++){
|
||||||
|
/* Find a node connected by the right edgetype */
|
||||||
|
if(!n->e[i].isConnected ||
|
||||||
|
n->e[i].isStrip != edgetype)
|
||||||
|
continue;
|
||||||
|
nn = &sm->nodes[n->e[i].node];
|
||||||
|
|
||||||
|
/* If the node has been visited already,
|
||||||
|
* there's a shorter path. */
|
||||||
|
if(nn->visited)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Don't allow non-strip edge between nodes of the same
|
||||||
|
* strip to prevent loops.
|
||||||
|
* Actually these edges are allowed under certain
|
||||||
|
* circumstances, but they require complex checks. */
|
||||||
|
if(edgetype == 0 &&
|
||||||
|
n->stripId == nn->stripId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
isEnd = IsEnd(nn);
|
||||||
|
|
||||||
|
/* Can't add end nodes to two lists, so skip. */
|
||||||
|
if(isEnd && edgetype == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nn->parent = n->e[i].otherEdge;
|
||||||
|
nn->visited = 1;
|
||||||
|
sm->nodes[nn->stripId].stripVisited = 1;
|
||||||
|
|
||||||
|
/* Search complete. */
|
||||||
|
if(isEnd && edgetype == 0)
|
||||||
|
return nn;
|
||||||
|
|
||||||
|
/* Found a valid node. */
|
||||||
|
searchNodes.append(&nn->inlist);
|
||||||
|
}
|
||||||
|
if(searchNodes.isEmpty())
|
||||||
|
return nil;
|
||||||
|
n = LLLinkGetData(searchNodes.link.next, StripNode, inlist);
|
||||||
|
n->inlist.remove();
|
||||||
|
edgetype = !edgetype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
resetGraph(StripMesh *sm)
|
||||||
|
{
|
||||||
|
StripNode *n;
|
||||||
|
for(int32 i = 0; i < sm->numNodes; i++){
|
||||||
|
n = &sm->nodes[i];
|
||||||
|
n->visited = 0;
|
||||||
|
n->stripVisited = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static StripNode*
|
||||||
|
walkStrip(StripMesh *sm, StripNode *start)
|
||||||
|
{
|
||||||
|
StripNode *n, *nn;
|
||||||
|
int32 last;
|
||||||
|
|
||||||
|
//printf("stripend: ");
|
||||||
|
//printNode(sm, start);
|
||||||
|
|
||||||
|
n = start;
|
||||||
|
last = -1;
|
||||||
|
for(;;n = nn){
|
||||||
|
n->visited = 0;
|
||||||
|
n->stripVisited = 0;
|
||||||
|
if(n->isEnd)
|
||||||
|
n->inlist.remove();
|
||||||
|
n->isEnd = 0;
|
||||||
|
|
||||||
|
if(IsEnd(n) && n != start)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
/* find next node */
|
||||||
|
nn = nil;
|
||||||
|
for(int32 i = 0; i < 3; i++){
|
||||||
|
if(!n->e[i].isStrip || i == last)
|
||||||
|
continue;
|
||||||
|
nn = &sm->nodes[n->e[i].node];
|
||||||
|
last = n->e[i].otherEdge;
|
||||||
|
nn->stripId = n->stripId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//printf(" next: ");
|
||||||
|
//printNode(sm, nn);
|
||||||
|
if(nn == nil)
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
applyTunnel(StripMesh *sm, StripNode *end, StripNode *start)
|
||||||
|
{
|
||||||
|
LinkList tmplist;
|
||||||
|
StripNode *n, *nn;
|
||||||
|
|
||||||
|
for(n = end; n != start; n = &sm->nodes[n->e[n->parent].node]){
|
||||||
|
//printf(" ");
|
||||||
|
//printNode(sm, n);
|
||||||
|
complementEdge(sm, &n->e[n->parent]);
|
||||||
|
}
|
||||||
|
//printf(" ");
|
||||||
|
//printNode(sm, start);
|
||||||
|
|
||||||
|
//printSmesh(sm);
|
||||||
|
//printf("-------\n");
|
||||||
|
tmplist.init();
|
||||||
|
while(!sm->endNodes.isEmpty()){
|
||||||
|
n = LLLinkGetData(sm->endNodes.link.next, StripNode, inlist);
|
||||||
|
/* take out of end list */
|
||||||
|
n->inlist.remove();
|
||||||
|
n->isEnd = 0;
|
||||||
|
/* no longer an end node */
|
||||||
|
if(!IsEnd(n))
|
||||||
|
continue;
|
||||||
|
// TODO: only walk strip if it was touched
|
||||||
|
/* set new id, walk strip and find other end */
|
||||||
|
n->stripId = n - sm->nodes;
|
||||||
|
nn = walkStrip(sm, n);
|
||||||
|
tmplist.append(&n->inlist);
|
||||||
|
n->isEnd = 1;
|
||||||
|
if(nn && n != nn){
|
||||||
|
tmplist.append(&nn->inlist);
|
||||||
|
nn->isEnd = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Move new end nodes to the real list. */
|
||||||
|
sm->endNodes = tmplist;
|
||||||
|
sm->endNodes.link.next->prev = &sm->endNodes.link;
|
||||||
|
sm->endNodes.link.prev->next = &sm->endNodes.link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tunnel(StripMesh *sm)
|
||||||
|
{
|
||||||
|
StripNode *n, *nn;
|
||||||
|
|
||||||
|
again:
|
||||||
|
FORLIST(lnk, sm->endNodes){
|
||||||
|
n = LLLinkGetData(lnk, StripNode, inlist);
|
||||||
|
// printf("searching %p %d\n", n, numStripEdges(n));
|
||||||
|
nn = findTunnel(sm, n);
|
||||||
|
// printf(" %p %p\n", n, nn);
|
||||||
|
|
||||||
|
if(nn){
|
||||||
|
applyTunnel(sm, nn, n);
|
||||||
|
resetGraph(sm);
|
||||||
|
/* applyTunnel changes sm->endNodes, so we have to
|
||||||
|
* jump out of the loop. */
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
resetGraph(sm);
|
||||||
|
}
|
||||||
|
printf("tunneling done!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each material:
|
||||||
|
* 1. build dual graph (collectFaces, connectNodes)
|
||||||
|
* 2. make some simple strip (buildStrips)
|
||||||
|
* 3. apply tunnel operator (tunnel)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Geometry::buildTristrips(void)
|
||||||
|
{
|
||||||
|
StripMesh smesh;
|
||||||
|
|
||||||
|
printf("%ld\n", sizeof(StripNode));
|
||||||
|
|
||||||
|
smesh.nodes = new StripNode[this->numTriangles];
|
||||||
|
for(int32 i = 0; i < this->numMaterials; i++){
|
||||||
|
smesh.loneNodes.init();
|
||||||
|
smesh.endNodes.init();
|
||||||
|
collectFaces(this, &smesh, i);
|
||||||
|
connectNodes(&smesh);
|
||||||
|
buildStrips(&smesh);
|
||||||
|
printSmesh(&smesh);
|
||||||
|
printf("-------\n");
|
||||||
|
//printLone(&smesh);
|
||||||
|
//printf("-------\n");
|
||||||
|
//printEnds(&smesh);
|
||||||
|
//printf("-------\n");
|
||||||
|
tunnel(&smesh);
|
||||||
|
//printf("-------\n");
|
||||||
|
//printEnds(&smesh);
|
||||||
|
}
|
||||||
|
delete[] smesh.nodes;
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user