LineSegs setVertexColor crash

Modifying something ynjh posted a while ago, I am experimenting with adding a simple motion trail to a moving object. I’d like to have a 10 segment line that starts with RGB(1,1,1,1) and gradually changes to RGB(1,1,1,0.1) at the end of the trail. Creating the segments works, but adding the

self.line.setVertexColor(index,1.0,1.0,1.0,alpha)

stuff crashes the app with this output:

DirectStart: Starting the game.
Known pipe types:
  osxGraphicsPipe
(all display modules loaded.)
1 0.1
1 0.1
2 0.2
1 0.1
2 0.2
3 0.3
1 0.1
2 0.2
3 0.3
4 0.4
Assertion failed: ((int)size <= _total_heap_array_size), function heap_free_array, file dtool/src/dtoolbase/memoryHook.cxx, line 347.
Abort trap

Notice that the script crashes randomly sooner or later, sometimes getting to index = 2, 4 or 6.
This is the modified code:

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task


class World(DirectObject):
  def __init__(self):
    self.drawingLine()

  def drawingLine(self):
    self.line = LineSegs()
    self.line.setThickness(4)
    self.line.setColor(1.0,1.0,1.0,1.0)
    self.lineNP=NodePath('')
    self.lineNP.setTransparency(True)
    self.points=[]
    self.lastMpos=None
    #taskMgr.add(self.mousePos, "mousePos")
    taskMgr.doMethodLater(0.1, self.mousePos, "mousePos")

  def mousePos(self, task):
    index = 0
    alpha = 0
    if base.mouseWatcherNode.hasMouse():
       mpos = base.mouseWatcherNode.getMouse()
       if mpos!=self.lastMpos:
          if self.lastMpos:
             self.points.append(Point3(self.lastMpos[0],0,self.lastMpos[1]))
          else:
             self.points.append(Point3(mpos[0],0,mpos[1]))
       #   self.line.reset()
          if len(self.points) >= 10:
             del self.points[0]
        #  print self.points
          self.line.moveTo(self.points[0])
          for p in self.points[1:]:
             #self.line.drawTo(p)
             index += 1
             alpha += 0.1
             print index, alpha
             self.line.setVertexColor(index,1.0,1.0,1.0,alpha)
             self.line.drawTo(p)
          self.lineNP.removeNode()
          self.lineNP=render2d.attachNewNode(self.line.create())
          self.lastMpos=Point2(mpos)
    return Task.again    #Task continues infinitely

w = World()
run()

In a related note, what does

LineSegs.reset()

actually do? Makes no visible change it seems to me.

When I change one line in the code above to

self.line.setVertexColor(len(self.points)-1,1.0,1.0,1.0,1.0)

I get a 10 segment white line as expected, but quitting the app Panda still crashes, only printing a “bus error” in Terminal. This is part of the error report:

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x000000000000000f
Crashed Thread:  0

Thread 0 Crashed:
0   com.apple.GeForce8xxxGLDriver 	0x185af778 gldReclaimBuffer + 24
1   com.apple.GeForce8xxxGLDriver 	0x185af87e gldDestroyBuffer + 30
2   GLEngine                      	0x184d17a2 gleFreeBufferObject + 162
3   GLEngine                      	0x1841a1f1 gleReleaseSharedState + 193
4   GLEngine                      	0x18418e83 gliDestroyContext + 83
5   com.apple.opengl              	0x912b8eb3 cglDestroyContext + 387
6   com.apple.opengl              	0x912b8b21 CGLDestroyContext + 33
7   com.apple.agl                 	0x900b871b aglDestroyContext + 187
8   libpandagl.dylib              	0x0665e1d7 osxGraphicsStateGuardian::~osxGraphicsStateGuardian() + 71
9   libpanda.dylib                	0x0247280e std::_Rb_tree<PointerTo<GraphicsStateGuardian>, PointerTo<GraphicsStateGuardian>, std::_Identity<PointerTo<GraphicsStateGuardian> >, std::less<PointerTo<GraphicsStateGuardian> >, pallocator_single<PointerTo<GraphicsStateGuardian> > >::_M_erase(std::_Rb_tree_node<PointerTo<GraphicsStateGuardian> >*) + 78
10  libpanda.dylib                	0x02457d44 GraphicsEngine::WindowRenderer::do_frame(GraphicsEngine*, Thread*) + 436
11  libpanda.dylib                	0x0245867d GraphicsEngine::render_frame() + 1117
12  libpanda.dylib                	0x02480172 Dtool_GraphicsEngine_render_frame_561(_object*, _object*, _object*) + 162
13  org.python.python             	0x0018f51e PyEval_EvalFrameEx + 17116
14  org.python.python             	0x00191173 PyEval_EvalCodeEx + 1638
15  org.python.python             	0x0013b488 PyFunction_SetClosure + 2667
16  org.python.python             	0x00121505 PyObject_Call + 50
17  org.python.python             	0x00129e3a PyMethod_New + 2457
18  org.python.python             	0x00121505 PyObject_Call + 50
19  libpanda.dylib                	0x024e0f5a Thread::call_python_func(_object*, _object*) + 858
20  libpanda.dylib                	0x024ffb52 PythonTask::do_python_task() + 850
21  libpanda.dylib                	0x024fec8b AsyncTask::unlock_and_do_task() + 235
22  libpanda.dylib                	0x0250d94b AsyncTaskChain::service_one_task(AsyncTaskChain::AsyncTaskChainThread*) + 491
23  libpanda.dylib                	0x0250e59e AsyncTaskChain::do_poll() + 286
24  libpanda.dylib                	0x0250e6ab AsyncTaskManager::poll() + 75
25  libpanda.dylib                	0x02522d12 Dtool_AsyncTaskManager_poll_121(_object*, _object*, _object*) + 162
26  org.python.python             	0x0018f51e PyEval_EvalFrameEx + 17116
27  org.python.python             	0x0018f700 PyEval_EvalFrameEx + 17598
28  org.python.python             	0x00191173 PyEval_EvalCodeEx + 1638
29  org.python.python             	0x0018f79d PyEval_EvalFrameEx + 17755
30  org.python.python             	0x0018f700 PyEval_EvalFrameEx + 17598
31  org.python.python             	0x00191173 PyEval_EvalCodeEx + 1638
32  org.python.python             	0x00191260 PyEval_EvalCode + 87
33  org.python.python             	0x001a883c PyErr_Display + 1896
34  org.python.python             	0x001a8e66 PyRun_FileExFlags + 135
35  org.python.python             	0x001aa7d2 PyRun_SimpleFileExFlags + 421
36  org.python.python             	0x001b5a57 Py_Main + 3095
37  org.python.pythonapp          	0x00001fca 0x1000 + 4042

My current Panda SDK is of July 2010.

Setting the alpha value to < 1.0 in the above line:

self.line.setVertexColor(len(self.points)-1,1.0,1.0,1.0,0.25)

reproduces the immediate crash above. A alpha problem?

DirectStart: Starting the game.
Known pipe types:
  osxGraphicsPipe
(all display modules loaded.)
1 0.1
1 0.1
2 0.2
Assertion failed: ((int)size <= _total_heap_array_size), function heap_free_array, file dtool/src/dtoolbase/memoryHook.cxx, line 347.
Abort trap

No crash or console output in all cases with Win7 64bit and a january build of panda

Using my code? Does it look like what I want to achieve?

Of course Im using your code. I dont know what you want to achieve exactly, on my machine its a motion trail of the ‘mouse’. Im not familiar with linesegs, but if you could change the tail color and use alpha then it would look more like a motion trail.

So anyway, you should probably just download a newer version of panda and try on that.

Well, that’s the point. I can get to the point where my mouse creates just a solid color trail. But I want it to fade from it’s start to it’s end. That’s what my code is supposed to do. So trying my code:

for p in self.points[1:]:
             #self.line.drawTo(p)
             index += 1
             alpha += 0.1
             print index, alpha
             self.line.setVertexColor(index,1.0,1.0,1.0,alpha)
             self.line.drawTo(p)

… do you see the trail fading or solid colored?

Nope.

but I dont get any error message

“No” is not a satisfying answer to a question with two equally relevant options.

The question was:

I would be glad if you could provide an answer to my question in a way that conveys helpful information to me.

I read half of the question I guess. No there is no fading.

There’s no fading because you made 2 mistakes :

  1. no setTransparency() call on the nodepath
  2. changing the vtx colors before the line is created

Another mistake is you increase the index and alpha before changing any vtx at all, so the tail vtx remains opaque.

So, this does it :

          self.line.moveTo(self.points[0])
          for p in self.points[1:]:
             self.line.drawTo(p)
          self.lineNP.removeNode()
          self.lineNP=render2d.attachNewNode(self.line.create())
          self.lineNP.setTransparency(True)
          self.lastMpos=Point2(mpos)
          for p in self.points[1:]:
             print index, alpha
             self.line.setVertexColor(index,1.0,1.0,1.0,alpha)
             index += 1
             alpha += 0.1

Well you did it once again. Your sample works 100% as expected.

Problem is that it doesnt integrate into my game. The code is too complex, propably too much to post here. But maybe you have an idea looking at this screen:

Notice the rocket trails that where produced firing at the target directly. They look OK, propably because they are < 10 segments. Issue 1 is that they should be removed on impact, but they are not, even though I call

uponDeath=linenp.removeNode

on thread creation. Removing a projectile calls for the uponDeath function via taskMgr.remove . The task is removed but the uponDeath function is not triggered, as I found out via a print command that never came.

Issue 2 comes into view looking at the longer lines. There it seems only the last 10 segments of the line are drawn correctly, propably because the other ones were not removed before. The points list is not the issue, it contains 10 Point3() items as it should.

My guess is that the

linenp.removeNode()

works on the wrong node, i.e. it loses reference on the “right” node. This could maybe be done via the return value of the task:

return task.again, linenp

but that produced problems I don’t understand.

This is the full code:

def createguided3dShot(vars):
	shot <- rocket node, works
	
	line = LineSegs()
	line.setThickness(3)
	faction = WeapList[weapname][15]
	line.setColor(self.colorFinder(faction)[0],self.colorFinder(faction)[1],self.colorFinder(faction)[2],0)
	linenp = NodePath("")
	points = []
	lastpos = None
	projlinetask = taskMgr.doMethodLater(0.1, self.createProjLine, "createProjLineTask",
	extraArgs=[shot, weapname, line, linenp, points, lastpos], appendTask=True, uponDeath=linenp.removeNode)
	shot.setPythonTag("projdottask", projlinetask) # will be finished on rocket impact
	
	return shot
	
def createProjLine(self, shot, weapname, line, linenp, points, lastpos, task):
	faction = WeapList[weapname][15]
	index = 0
	alpha = 0
	shotpos=Point3(shot.getX(),shot.getY(),0)
	if lastpos:
		points.append(Point3(lastpos[0],lastpos[1],0))
	else:
		points.append(shotpos)
	line.reset()
	print points
	if len(points) >= 10:
		del points[0]
	line.moveTo(points[0])
	for p in points[1:]:
		line.drawTo(p)
	linenp.removeNode()
	linenp = render.attachNewNode(line.create())
	linenp.setTransparency(True)
	linenp.setLightOff()
	linenp.setShaderOff()
	lastpos = Point3(shotpos)
	for p in points[1:]:
		line.setVertexColor(index,self.colorFinder(faction)[0],self.colorFinder(faction)[1],self.colorFinder(faction)[2],alpha)
		index += 1
		alpha += 0.1
	return task.again
linenp = render.attachNewNode(line.create())

You attach the line to render, not to your linenp, so the uponDeath func removes that empty node.

You could do it this way :

  1. in createguided3dShot :
linenp = render.attachNewNode("")
  1. in createguided3dShot, don’t remove linenp, but its children by :
linenp.removeChildren()

and reparent the line to it :

linenp.attachNewNode(line.create())

instead of to render.

That works, thank you very much!
One problem remains. The uponDeath call is still not triggered in my deleteProjectile function, which is called when the projectile impacts or expires. Now the thread ends when it’s removed, that’s not the problem. It’s just that taskMgr.remove(task) does not trigger the uponDeath.
As a result the last 10 segments stay in the universe.

It does. How do you remove the task ?

in Effects:

projlinetask = taskMgr.doMethodLater(0.1, (...), appendTask=True, uponDeath=linenp.removeNode)
   shot.setPythonTag("projdottask", projlinetask) # will be finished on rocket impact

and it does not make a difference what I use: linenp.removeNode
linenp.removeChildren
or some function pointer to a function that just prints some message.

in Environment:

taskMgr.remove(shipprojnode.getPythonTag("projdottask"))

The task ends, but I’m pretty sure the uponDeath is not triggered. When I set

return task.done

instead of .again in my task function (just for testing, doesnt make sense of course), the uponDeath is triggered.

I also tried

if task.done:
			print "delete proj task"
		return task.again

at the end of the createProjLine task function, but that doesnt print anything.

EDIT:
It works when I use:

uponDeath=lambda task: linenp.removeNode()

At least the trails are being removed. Later I will have to find a way to gradually fade them away. Any ideas on this one?

That’s probably because you still store a reference to the task in the “projdottask” tag. You’d need to clear that tag in order for the task to destruct.