//----------------------------------------------- // Synapse Gaming - Lighting System // Copyright © Synapse Gaming 2003 // Written by John Kabus //----------------------------------------------- #include "lightingSystem/sgLighting.h" #include "lightingSystem/sgDecalProjector.h" #include "sim/decalManager.h" #include "sim/netConnection.h" #include "sceneGraph/sceneState.h" extern bool gEditingMission; class sgDecalProjector : public GameBase { typedef GameBase Parent; DecalData *mDataBlock; bool onNewDataBlock(GameBaseData* dptr); protected: bool sgInitNeeded; bool sgProjection; Point3F sgProjectionPoint; Point3F sgProjectionNormal; bool onAdd(); void onRemove(); void sgResetProjection(); void sgProject(); public: sgDecalProjector(); void inspectPostApply(); void setTransform(const MatrixF &mat); bool prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState); void renderObject(SceneState *state, SceneRenderImage *image); U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); void unpackUpdate(NetConnection *con, BitStream *stream); DECLARE_CONOBJECT(sgDecalProjector); }; IMPLEMENT_CO_NETOBJECT_V1(sgDecalProjector); sgDecalProjector::sgDecalProjector() { mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType; mNetFlags.set(Ghostable | ScopeAlways); mDataBlock = NULL; sgProjection = false; sgProjectionPoint = Point3F(0.0f, 0.0f, 0.0f); sgProjectionNormal = Point3F(0.0f, 0.0f, 0.0f); // for after load relinking... sgInitNeeded = true; } bool sgDecalProjector::onAdd() { if(!Parent::onAdd()) return false; mObjBox.min.set( -0.5, -0.5, -0.5 ); mObjBox.max.set( 0.5, 0.5, 0.5 ); resetWorldBox(); setRenderTransform(mObjToWorld); addToScene(); return true; } void sgDecalProjector::onRemove() { if(isClientObject()) gDecalManager->ageDecal(getId()); removeFromScene(); Parent::onRemove(); } bool sgDecalProjector::onNewDataBlock(GameBaseData* dptr) { mDataBlock = dynamic_cast(dptr); return Parent::onNewDataBlock(dptr); } bool sgDecalProjector::prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState) { if(!gEditingMission) return false; if(isLastState(state, stateKey)) return false; setLastState(state, stateKey); if(state->isObjectRendered(this)) { SceneRenderImage* image = new SceneRenderImage; image->obj = this; image->isTranslucent = true; image->sortType = SceneRenderImage::EndSort; state->insertRenderImage(image); } return false; } void sgDecalProjector::renderObject(SceneState *state, SceneRenderImage *image) { if(gEditingMission) { // render the directional line... glBlendFunc(GL_ONE,GL_ZERO); glEnable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); Point3F vector = SG_STATIC_SPOT_VECTOR_NORMALIZED * 10.0f; Point3F origin = Point3F(0, 0, 0); Point3F point = vector; mObjToWorld.mulP(origin); mObjToWorld.mulP(point); glColor3f(0, 1, 0); glBegin(GL_LINES); glVertex3fv(origin); glVertex3fv(point); glEnd(); } } void sgDecalProjector::sgResetProjection() { sgProjection = false; sgProjectionPoint = Point3F(0.0f, 0.0f, 0.0f); sgProjectionNormal = Point3F(0.0f, 0.0f, 0.0f); if(isClientObject()) return; Point3F pos = getPosition(); Point3F normal = SG_STATIC_SPOT_VECTOR_NORMALIZED * 100.0f; getTransform().mulV(normal); RayInfo info; if(!gServerContainer.castRay(pos, (pos + normal), InteriorObjectType | TerrainObjectType, &info)) { Con::errorf("Error in _sgDropDecal: no drop object found."); return; } sgProjection = true; sgProjectionPoint = info.point; sgProjectionNormal = info.normal; setMaskBits(0xffffffff); } void sgDecalProjector::sgProject() { if((isServerObject()) || (!mDataBlock)) return; // use the instead of getId()... // id's are flaky in zones... U32 ownerid = U32(this); gDecalManager->ageDecal(ownerid); if(!sgProjection) return; Point3F tandir; getTransform().getColumn(0, &tandir); gDecalManager->addDecal(sgProjectionPoint, tandir, sgProjectionNormal, getScale(), mDataBlock, ownerid); } void sgDecalProjector::setTransform(const MatrixF & mat) { Parent::setTransform(mat); sgResetProjection(); setMaskBits(0xffffffff); } U32 sgDecalProjector::packUpdate(NetConnection *con, U32 mask, BitStream *stream) { U32 res = Parent::packUpdate(con, mask, stream); if(sgInitNeeded && isServerObject()) { sgInitNeeded = false; sgResetProjection(); } stream->writeAffineTransform(mObjToWorld); if(stream->writeFlag(sgProjection)) { // this is a joke right (no Point3F support)?!? stream->write(sgProjectionPoint.x); stream->write(sgProjectionPoint.y); stream->write(sgProjectionPoint.z); stream->write(sgProjectionNormal.x); stream->write(sgProjectionNormal.y); stream->write(sgProjectionNormal.z); } return res; } void sgDecalProjector::unpackUpdate(NetConnection *con, BitStream *stream) { Parent::unpackUpdate(con, stream); MatrixF ObjectMatrix; stream->readAffineTransform(&ObjectMatrix); setTransform(ObjectMatrix); sgProjection = stream->readFlag(); if(sgProjection) { // this is a joke right (no Point3F support)?!? stream->read(&sgProjectionPoint.x); stream->read(&sgProjectionPoint.y); stream->read(&sgProjectionPoint.z); stream->read(&sgProjectionNormal.x); stream->read(&sgProjectionNormal.y); stream->read(&sgProjectionNormal.z); } sgProject(); } void sgDecalProjector::inspectPostApply() { Parent::inspectPostApply(); sgResetProjection(); setMaskBits(0xffffffff); } //----------------------------------------------- ConsoleFunction(_sgCreateDecal, void, 6, 6, "(Point3F pos, Point3F tandir, Point3F norm, " "Point3F scale, decalDataBlock) - this method must be called on the client side!") { // is this the client side? // doesn't work... //if(gDecalManager->isServerObject()) // return; Point3F pos = Point3F(0, 0, 0); Point3F tandir = Point3F(1, 0, 0); Point3F normal = Point3F(0, 0, 1); Point3F scale = Point3F(1, 1, 1); DecalData *decaldata = NULL; dSscanf(argv[1],"%f %f %f",&pos.x,&pos.y,&pos.z); dSscanf(argv[2],"%f %f %f",&tandir.x,&tandir.y,&tandir.z); dSscanf(argv[3],"%f %f %f",&normal.x,&normal.y,&normal.z); dSscanf(argv[4],"%f %f %f",&scale.x,&scale.y,&scale.z); decaldata = dynamic_cast(Sim::findObject(argv[5])); if(!decaldata) return; gDecalManager->addDecal(pos, tandir, normal, scale, decaldata); } ConsoleFunction(_sgDropDecal, void, 6, 6, "(Point3F pos, Point3F tandir, Point3F norm, " "Point3F scale, decalDataBlock) - this method must be called on the client side! " "This method drops a decal onto the interior or " "terrain directly below the given position.") { // is this the client side? // doesn't work... //if(!gDecalManager->isGhost()) // return; Point3F pos = Point3F(0, 0, 0); Point3F tandir = Point3F(1, 0, 0); Point3F normal = Point3F(0, 0, 1); Point3F scale = Point3F(1, 1, 1); DecalData *decaldata = NULL; dSscanf(argv[1],"%f %f %f",&pos.x,&pos.y,&pos.z); dSscanf(argv[2],"%f %f %f",&tandir.x,&tandir.y,&tandir.z); dSscanf(argv[3],"%f %f %f",&normal.x,&normal.y,&normal.z); dSscanf(argv[4],"%f %f %f",&scale.x,&scale.y,&scale.z); decaldata = dynamic_cast(Sim::findObject(argv[5])); if(!decaldata) return; RayInfo info; if(!gClientContainer.castRay(pos, (pos + Point3F(0, 0, -100)), InteriorObjectType | TerrainObjectType, &info)) { Con::errorf("Error in _sgDropDecal: no drop object found."); return; } pos = info.point; normal = info.normal; gDecalManager->addDecal(pos, tandir, normal, scale, decaldata); }