/* BobToolz plugin for GtkRadiant Copyright (C) 2001 Gordon Biggans This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "DTrainDrawer.h" #include #include "str.h" #include "DPoint.h" #include "DPlane.h" #include "DBrush.h" #include "DEPair.h" #include "DPatch.h" #include "DEntity.h" #include "misc.h" #include "funchandlers.h" #include "iglrender.h" #include "ientity.h" #include "math/matrix.h" #include "dialogs/dialogs-gtk.h" DTrainDrawer::DTrainDrawer() { m_bDisplay = false; BuildPaths(); constructShaders(); GlobalShaderCache().attachRenderable(*this); } DTrainDrawer::~DTrainDrawer(void) { GlobalShaderCache().detachRenderable(*this); destroyShaders(); ClearPoints(); ClearSplines(); } void DTrainDrawer::ClearSplines() { for(std::list::const_iterator deadSpline = m_splineList.begin(); deadSpline != m_splineList.end(); deadSpline++) { (*deadSpline)->m_pointList.clear(); (*deadSpline)->m_vertexList.clear(); delete (*deadSpline); } m_splineList.clear(); } void DTrainDrawer::ClearPoints() { for(std::list::const_iterator deadPoint = m_pointList.begin(); deadPoint != m_pointList.end(); deadPoint++) { delete *deadPoint; } m_pointList.clear(); } void CalculateSpline_r(vec3_t* v, int count, vec3_t out, float tension) { vec3_t dist; if(count < 2) { return; } if(count == 2) { VectorSubtract( v[1], v[0], dist ); VectorMA(v[0], tension, dist, out); return; } vec3_t* v2 = new vec3_t[count-1]; for( int i = 0; i < count-1; i++ ) { VectorSubtract( v[i+1], v[i], dist ); VectorMA(v[i], tension, dist, v2[i]); } CalculateSpline_r( v2, count-1, out, tension); delete[] v2; } void DTrainDrawer::render(RenderStateFlags state) const { for(std::list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { splinePoint_t* pSP = (*sp); glBegin(GL_LINE_STRIP); for(std::list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { glVertex3fv((*v)._pnt); } glEnd(); } } const char* DTrainDrawer_state_wireframe = "$bobtoolz/traindrawer/wireframe"; const char* DTrainDrawer_state_solid = "$bobtoolz/traindrawer/solid"; void DTrainDrawer::constructShaders() { OpenGLState state; GlobalOpenGLStateLibrary().getDefaultState(state); state.m_state = RENDER_COLOURWRITE|RENDER_DEPTHWRITE|RENDER_BLEND; state.m_sort = OpenGLState::eSortOverlayFirst; state.m_linewidth = 1; state.m_colour[0] = 1; state.m_colour[1] = 0; state.m_colour[2] = 0; state.m_colour[3] = 1; state.m_linewidth = 1; GlobalOpenGLStateLibrary().insert(DTrainDrawer_state_wireframe, state); state.m_colour[0] = 1; state.m_colour[1] = 1; state.m_colour[2] = 1; state.m_colour[3] = 1; state.m_linewidth = 2; GlobalOpenGLStateLibrary().insert(DTrainDrawer_state_solid, state); m_shader_wireframe = GlobalShaderCache().capture(DTrainDrawer_state_wireframe); m_shader_solid = GlobalShaderCache().capture(DTrainDrawer_state_solid); } void DTrainDrawer::destroyShaders() { GlobalOpenGLStateLibrary().erase(DTrainDrawer_state_wireframe); GlobalOpenGLStateLibrary().erase(DTrainDrawer_state_solid); GlobalShaderCache().release(DTrainDrawer_state_wireframe); GlobalShaderCache().release(DTrainDrawer_state_solid); } void DTrainDrawer::renderSolid(Renderer& renderer, const VolumeTest& volume) const { if(!m_bDisplay) { return; } renderer.SetState(m_shader_wireframe, Renderer::eWireframeOnly); renderer.SetState(m_shader_solid, Renderer::eFullMaterials); renderer.addRenderable(*this, g_matrix4_identity); } void DTrainDrawer::renderWireframe(Renderer& renderer, const VolumeTest& volume) const { renderSolid(renderer, volume); } void AddSplineControl(const char* control, splinePoint_t* pSP) { controlPoint_t cp; strncpy(cp.strName, control, 64); pSP->m_pointList.push_front(cp); } class EntityBuildPaths { mutable DEntity e; DTrainDrawer& drawer; public: EntityBuildPaths(DTrainDrawer& drawer) : drawer(drawer) { } void operator()(scene::Instance& instance) const { e.ClearEPairs(); e.LoadEPairList(Node_getEntity(instance.path().top())); const char* classname = e.m_Classname.GetBuffer(); const char* target; const char* control; const char* targetname; vec3_t vOrigin; e.SpawnString("targetname", NULL, &targetname); e.SpawnVector("origin", "0 0 0", vOrigin); if(!strcmp(classname, "info_train_spline_main")) { if(!targetname) { globalOutputStream() << "info_train_spline_main with no targetname"; return; } e.SpawnString("target", NULL, &target); if(!target) { drawer.AddControlPoint( targetname, vOrigin ); } else { splinePoint_t* pSP = drawer.AddSplinePoint( targetname, target, vOrigin ); e.SpawnString("control", NULL, &control); if(control) { AddSplineControl( control, pSP ); for(int j = 2;; j++) { char buffer[16]; sprintf(buffer, "control%i", j); e.SpawnString(buffer, NULL, &control); if(!control) { break; } AddSplineControl( control, pSP ); } } } } else if(!strcmp(classname, "info_train_spline_control")) { if(!targetname) { globalOutputStream() << "info_train_spline_control with no targetname"; return; } drawer.AddControlPoint( targetname, vOrigin ); } } }; void DTrainDrawer::BuildPaths() { Scene_forEachEntity(EntityBuildPaths(*this)); std::list::const_iterator sp; for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { splinePoint_t* pSP = (*sp); controlPoint_t* pTarget = FindControlPoint( pSP->strTarget ); if(!pTarget) { globalOutputStream() << "couldn't find target " << pSP->strTarget; return; // continue; } pSP->pTarget = pTarget; for(std::list::iterator cp = pSP->m_pointList.begin(); cp != pSP->m_pointList.end(); cp++) { controlPoint_t* pControl = FindControlPoint( (*cp).strName ); if(!pControl) { globalOutputStream() << "couldn't find control " << (*cp).strName; return; } VectorCopy(pControl->vOrigin, (*cp).vOrigin); } } m_bDisplay = true; for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { splinePoint_t* pSP = (*sp); DPoint out; if(!pSP->pTarget) { continue; } std::size_t count = pSP->m_pointList.size() + 2; vec3_t* v = new vec3_t[count]; VectorCopy(pSP->point.vOrigin, v[0]); int i = 1; for(std::list::reverse_iterator cp = pSP->m_pointList.rbegin(); cp != pSP->m_pointList.rend(); cp++) { VectorCopy((*cp).vOrigin, v[i]); i++; } VectorCopy(pSP->pTarget->vOrigin, v[i]); for (float tension = 0.0f; tension <= 1.f; tension += 0.01f) { CalculateSpline_r(v, static_cast(count), out._pnt, tension); pSP->m_vertexList.push_front(out); } delete[] v; VectorCopy(pSP->pTarget->vOrigin, out._pnt); pSP->m_vertexList.push_front(out); } SceneChangeNotify(); } void DTrainDrawer::AddControlPoint(const char* name, vec_t* origin) { controlPoint_t* pCP = new controlPoint_t; strncpy(pCP->strName, name, 64); VectorCopy( origin, pCP->vOrigin ); m_pointList.push_back( pCP ); } splinePoint_t* DTrainDrawer::AddSplinePoint(const char* name, const char* target, vec_t* origin) { splinePoint_t* pSP = new splinePoint_t; strncpy(pSP->point.strName, name, 64); strncpy(pSP->strTarget, target, 64); VectorCopy( origin, pSP->point.vOrigin ); m_splineList.push_back( pSP ); return pSP; } controlPoint_t* DTrainDrawer::FindControlPoint(const char* name) { for(std::list::const_iterator cp = m_pointList.begin(); cp != m_pointList.end(); cp++) { if(!strcmp(name, (*cp)->strName)) { return (*cp); } } for(std::list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { if(!strcmp(name, (*sp)->point.strName)) { return &((*sp)->point); } } return NULL; }