class HtmlView(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory('HtmlView') useHalfTexture = base.config.GetBool('news-half-texture', 0) def __init__(self, parent=aspect2d): global GlobalWebcore self.parent = parent self.mx = 0 self.my = 0 self.htmlFile = 'index.html' self.transparency = False if GlobalWebcore: pass else: GlobalWebcore = AwWebCore(AwWebCore.LOGVERBOSE, True, AwWebCore.PFBGRA) GlobalWebcore.setBaseDirectory('.') for errResponse in xrange(400, 600): GlobalWebcore.setCustomResponsePage(errResponse, 'error.html') self.webView = GlobalWebcore.createWebView(WEB_WIDTH, WEB_HEIGHT, self.transparency, False, 70) frameName = '' inGameNewsUrl = self.getInGameNewsUrl() self.imgBuffer = array.array('B') for i in xrange(WEB_WIDTH * WEB_HEIGHT): self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(255) if self.useHalfTexture: self.leftBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(255) self.rightBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(255) self.setupTexture() if self.useHalfTexture: self.setupHalfTextures() self.accept('mouse1', self.mouseDown, [AwWebView.LEFTMOUSEBTN]) self.accept('mouse3', self.mouseDown, [AwWebView.RIGHTMOUSEBTN]) self.accept('mouse1-up', self.mouseUp, [AwWebView.LEFTMOUSEBTN]) self.accept('mouse3-up', self.mouseUp, [AwWebView.RIGHTMOUSEBTN]) def getInGameNewsUrl(self): result = base.config.GetString( 'fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/') override = base.config.GetString('in-game-news-url', '') if override: self.notify.info( 'got an override url, using %s for in a game news' % override) result = override else: try: launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '') if launcherUrl: result = launcherUrl self.notify.info( 'got GAME_IN_GAME_NEWS_URL from launcher using %s' % result) else: self.notify.info( 'blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) except: self.notify.warning( 'got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) return result def setupTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT) cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) bottomRightX = WEB_WIDTH_PIXELS / float(WEB_WIDTH + 1) bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1) cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1)) card = cm.generate() self.quad = NodePath(card) self.quad.reparentTo(self.parent) self.guiTex = Texture('guiTex') self.guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.guiTex.setMinfilter(Texture.FTLinear) self.guiTex.setKeepRamImage(True) self.guiTex.makeRamImage() self.guiTex.setWrapU(Texture.WMRepeat) self.guiTex.setWrapV(Texture.WMRepeat) ts = TextureStage('webTS') self.quad.setTexture(ts, self.guiTex) self.quad.setTexScale(ts, 1.0, -1.0) self.quad.setTransparency(0) self.quad.setTwoSided(True) self.quad.setColor(1.0, 1.0, 1.0, 1.0) self.calcMouseLimits() def setupHalfTextures(self): self.setupLeftTexture() self.setupRightTexture() self.fullPnmImage = PNMImage(WEB_WIDTH, WEB_HEIGHT, 4) self.leftPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) self.rightPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) def setupLeftTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) cm.setFrame(-htmlWidth / 2.0, 0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.leftQuad = NodePath(card) self.leftQuad.reparentTo(self.parent) self.leftGuiTex = Texture('guiTex') self.leftGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.leftGuiTex.setKeepRamImage(True) self.leftGuiTex.makeRamImage() self.leftGuiTex.setWrapU(Texture.WMClamp) self.leftGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('leftWebTS') self.leftQuad.setTexture(ts, self.leftGuiTex) self.leftQuad.setTexScale(ts, 1.0, -1.0) self.leftQuad.setTransparency(0) self.leftQuad.setTwoSided(True) self.leftQuad.setColor(1.0, 1.0, 1.0, 1.0) def setupRightTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) cm.setFrame(0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.rightQuad = NodePath(card) self.rightQuad.reparentTo(self.parent) self.rightGuiTex = Texture('guiTex') self.rightGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.rightGuiTex.setKeepRamImage(True) self.rightGuiTex.makeRamImage() self.rightGuiTex.setWrapU(Texture.WMClamp) self.rightGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('rightWebTS') self.rightQuad.setTexture(ts, self.rightGuiTex) self.rightQuad.setTexScale(ts, 1.0, -1.0) self.rightQuad.setTransparency(0) self.rightQuad.setTwoSided(True) self.rightQuad.setColor(1.0, 1.0, 1.0, 1.0) def calcMouseLimits(self): ll = Point3() ur = Point3() self.quad.calcTightBounds(ll, ur) self.notify.debug('ll=%s ur=%s' % (ll, ur)) offset = self.quad.getPos(aspect2d) self.notify.debug('offset = %s ' % offset) ll.setZ(ll.getZ() + offset.getZ()) ur.setZ(ur.getZ() + offset.getZ()) self.notify.debug('new LL=%s, UR=%s' % (ll, ur)) relPointll = self.quad.getRelativePoint(aspect2d, ll) self.notify.debug('relPoint = %s' % relPointll) self.mouseLL = (aspect2d.getScale()[0] * ll[0], aspect2d.getScale()[2] * ll[2]) self.mouseUR = (aspect2d.getScale()[0] * ur[0], aspect2d.getScale()[2] * ur[2]) self.notify.debug('original mouseLL=%s, mouseUR=%s' % (self.mouseLL, self.mouseUR)) def writeTex(self, filename='guiText.png'): self.notify.debug('writing texture') self.guiTex.generateRamMipmapImages() self.guiTex.write(filename) def toggleRotation(self): if self.interval.isPlaying(): self.interval.finish() else: self.interval.loop() def mouseDown(self, button): messenger.send('wakeup') self.webView.injectMouseDown(button) def mouseUp(self, button): self.webView.injectMouseUp(button) def reload(self): pass def zoomIn(self): self.webView.zoomIn() def zoomOut(self): self.webView.zoomOut() def toggleTransparency(self): self.transparency = not self.transparency self.webView.setTransparent(self.transparency) def update(self, task): if base.mouseWatcherNode.hasMouse(): x, y = self._translateRelativeCoordinates( base.mouseWatcherNode.getMouseX(), base.mouseWatcherNode.getMouseY()) if self.mx - x != 0 or self.my - y != 0: self.webView.injectMouseMove(x, y) self.mx, self.my = x, y if self.webView.isDirty(): self.webView.render(self.imgBuffer.buffer_info()[0], WEB_WIDTH * 4, 4) Texture.setTexturesPower2(2) textureBuffer = self.guiTex.modifyRamImage() textureBuffer.setData(self.imgBuffer.tostring()) if self.useHalfTexture: self.guiTex.store(self.fullPnmImage) self.leftPnmImage.copySubImage(self.fullPnmImage, 0, 0, 0, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.rightPnmImage.copySubImage(self.fullPnmImage, 0, 0, WEB_HALF_WIDTH, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.leftGuiTex.load(self.leftPnmImage) self.rightGuiTex.load(self.rightPnmImage) self.quad.hide() Texture.setTexturesPower2(1) GlobalWebcore.update() return Task.cont def _translateRelativeCoordinates(self, x, y): sx = int((x - self.mouseLL[0]) / (self.mouseUR[0] - self.mouseLL[0]) * WEB_WIDTH_PIXELS) sy = WEB_HEIGHT_PIXELS - int( (y - self.mouseLL[1]) / (self.mouseUR[1] - self.mouseLL[1]) * WEB_HEIGHT_PIXELS) return (sx, sy) def unload(self): self.ignoreAll() self.webView.destroy() self.webView = None return def onCallback(self, name, args): if name == 'requestFPS': pass def onBeginNavigation(self, url, frameName): pass def onBeginLoading(self, url, frameName, statusCode, mimeType): pass def onFinishLoading(self): self.notify.debug('finished loading') def onReceiveTitle(self, title, frameName): pass def onChangeTooltip(self, tooltip): pass def onChangeCursor(self, cursor): pass def onChangeKeyboardFocus(self, isFocused): pass def onChangeTargetURL(self, url): pass
class HtmlView(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory('HtmlView') useHalfTexture = config.GetBool('news-half-texture', 0) def __init__(self, parent = aspect2d): global GlobalWebcore self.parent = parent self.mx = 0 self.my = 0 self.htmlFile = 'index.html' self.transparency = False if GlobalWebcore: pass else: GlobalWebcore = AwWebCore(AwWebCore.LOGVERBOSE, True, AwWebCore.PFBGRA) GlobalWebcore.setBaseDirectory('.') for errResponse in xrange(400, 600): GlobalWebcore.setCustomResponsePage(errResponse, 'error.html') self.webView = GlobalWebcore.createWebView(WEB_WIDTH, WEB_HEIGHT, self.transparency, False, 70) frameName = '' inGameNewsUrl = self.getInGameNewsUrl() self.imgBuffer = array.array('B') for i in xrange(WEB_WIDTH * WEB_HEIGHT): self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(255) if self.useHalfTexture: self.leftBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(255) self.rightBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(255) self.setupTexture() if self.useHalfTexture: self.setupHalfTextures() self.accept('mouse1', self.mouseDown, [AwWebView.LEFTMOUSEBTN]) self.accept('mouse3', self.mouseDown, [AwWebView.RIGHTMOUSEBTN]) self.accept('mouse1-up', self.mouseUp, [AwWebView.LEFTMOUSEBTN]) self.accept('mouse3-up', self.mouseUp, [AwWebView.RIGHTMOUSEBTN]) def getInGameNewsUrl(self): result = config.GetString('fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/') override = config.GetString('in-game-news-url', '') if override: self.notify.info('got an override url, using %s for in a game news' % override) result = override else: try: launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '') if launcherUrl: result = launcherUrl self.notify.info('got GAME_IN_GAME_NEWS_URL from launcher using %s' % result) else: self.notify.info('blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) except: self.notify.warning('got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) return result def setupTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT) cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) bottomRightX = WEB_WIDTH_PIXELS / float(WEB_WIDTH + 1) bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1) cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1)) card = cm.generate() self.quad = NodePath(card) self.quad.reparentTo(self.parent) self.guiTex = Texture('guiTex') self.guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.guiTex.setMinfilter(Texture.FTLinear) self.guiTex.setKeepRamImage(True) self.guiTex.makeRamImage() self.guiTex.setWrapU(Texture.WMRepeat) self.guiTex.setWrapV(Texture.WMRepeat) ts = TextureStage('webTS') self.quad.setTexture(ts, self.guiTex) self.quad.setTexScale(ts, 1.0, -1.0) self.quad.setTransparency(0) self.quad.setTwoSided(True) self.quad.setColor(1.0, 1.0, 1.0, 1.0) self.calcMouseLimits() def setupHalfTextures(self): self.setupLeftTexture() self.setupRightTexture() self.fullPnmImage = PNMImage(WEB_WIDTH, WEB_HEIGHT, 4) self.leftPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) self.rightPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) def setupLeftTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) cm.setFrame(-htmlWidth / 2.0, 0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.leftQuad = NodePath(card) self.leftQuad.reparentTo(self.parent) self.leftGuiTex = Texture('guiTex') self.leftGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.leftGuiTex.setKeepRamImage(True) self.leftGuiTex.makeRamImage() self.leftGuiTex.setWrapU(Texture.WMClamp) self.leftGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('leftWebTS') self.leftQuad.setTexture(ts, self.leftGuiTex) self.leftQuad.setTexScale(ts, 1.0, -1.0) self.leftQuad.setTransparency(0) self.leftQuad.setTwoSided(True) self.leftQuad.setColor(1.0, 1.0, 1.0, 1.0) def setupRightTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) cm.setFrame(0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.rightQuad = NodePath(card) self.rightQuad.reparentTo(self.parent) self.rightGuiTex = Texture('guiTex') self.rightGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.rightGuiTex.setKeepRamImage(True) self.rightGuiTex.makeRamImage() self.rightGuiTex.setWrapU(Texture.WMClamp) self.rightGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('rightWebTS') self.rightQuad.setTexture(ts, self.rightGuiTex) self.rightQuad.setTexScale(ts, 1.0, -1.0) self.rightQuad.setTransparency(0) self.rightQuad.setTwoSided(True) self.rightQuad.setColor(1.0, 1.0, 1.0, 1.0) def calcMouseLimits(self): ll = Point3() ur = Point3() self.quad.calcTightBounds(ll, ur) self.notify.debug('ll=%s ur=%s' % (ll, ur)) offset = self.quad.getPos(aspect2d) self.notify.debug('offset = %s ' % offset) ll.setZ(ll.getZ() + offset.getZ()) ur.setZ(ur.getZ() + offset.getZ()) self.notify.debug('new LL=%s, UR=%s' % (ll, ur)) relPointll = self.quad.getRelativePoint(aspect2d, ll) self.notify.debug('relPoint = %s' % relPointll) self.mouseLL = (aspect2d.getScale()[0] * ll[0], aspect2d.getScale()[2] * ll[2]) self.mouseUR = (aspect2d.getScale()[0] * ur[0], aspect2d.getScale()[2] * ur[2]) self.notify.debug('original mouseLL=%s, mouseUR=%s' % (self.mouseLL, self.mouseUR)) def writeTex(self, filename = 'guiText.png'): self.notify.debug('writing texture') self.guiTex.generateRamMipmapImages() self.guiTex.write(filename) def toggleRotation(self): if self.interval.isPlaying(): self.interval.finish() else: self.interval.loop() def mouseDown(self, button): messenger.send('wakeup') self.webView.injectMouseDown(button) def mouseUp(self, button): self.webView.injectMouseUp(button) def reload(self): pass def zoomIn(self): self.webView.zoomIn() def zoomOut(self): self.webView.zoomOut() def toggleTransparency(self): self.transparency = not self.transparency self.webView.setTransparent(self.transparency) def update(self, task): if base.mouseWatcherNode.hasMouse(): x, y = self._translateRelativeCoordinates(base.mouseWatcherNode.getMouseX(), base.mouseWatcherNode.getMouseY()) if self.mx - x != 0 or self.my - y != 0: self.webView.injectMouseMove(x, y) self.mx, self.my = x, y if self.webView.isDirty(): self.webView.render(self.imgBuffer.buffer_info()[0], WEB_WIDTH * 4, 4) Texture.setTexturesPower2(2) textureBuffer = self.guiTex.modifyRamImage() textureBuffer.setData(self.imgBuffer.tostring()) if self.useHalfTexture: self.guiTex.store(self.fullPnmImage) self.leftPnmImage.copySubImage(self.fullPnmImage, 0, 0, 0, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.rightPnmImage.copySubImage(self.fullPnmImage, 0, 0, WEB_HALF_WIDTH, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.leftGuiTex.load(self.leftPnmImage) self.rightGuiTex.load(self.rightPnmImage) self.quad.hide() Texture.setTexturesPower2(1) GlobalWebcore.update() return Task.cont def _translateRelativeCoordinates(self, x, y): sx = int((x - self.mouseLL[0]) / (self.mouseUR[0] - self.mouseLL[0]) * WEB_WIDTH_PIXELS) sy = WEB_HEIGHT_PIXELS - int((y - self.mouseLL[1]) / (self.mouseUR[1] - self.mouseLL[1]) * WEB_HEIGHT_PIXELS) return (sx, sy) def unload(self): self.ignoreAll() self.webView.destroy() self.webView = None return def onCallback(self, name, args): if name == 'requestFPS': pass def onBeginNavigation(self, url, frameName): pass def onBeginLoading(self, url, frameName, statusCode, mimeType): pass def onFinishLoading(self): self.notify.debug('finished loading') def onReceiveTitle(self, title, frameName): pass def onChangeTooltip(self, tooltip): pass def onChangeCursor(self, cursor): pass def onChangeKeyboardFocus(self, isFocused): pass def onChangeTargetURL(self, url): pass
class GXOStar(GXOBase): def __init__(self, parent=render, pos=Vec3(50, 0, 0)): GXOBase.__init__(self, parent, pos) self._initializeFlare() def _initializeFlare(self): # Parameters self.distance = 130000.0 self.threshold = 0.3 self.radius = 0.8 self.strength = 1.0 self.suncolor = Vec4(1, 1, 1, 1) self.suncardcolor = Vec4(1, 1, 0, 0) # Initialize some values self.obscured = 0.0 # flaredata will hold the rendered image self.flaredata = PNMImage() # flaretexture will store the rendered buffer self.flaretexture = Texture() # Create a 10x10 texture buffer for the flare self.flarebuffer = base.win.makeTextureBuffer("Flare Buffer", 10, 10) # Attach the texture to the buffer self.flarebuffer.addRenderTexture(self.flaretexture, GraphicsOutput.RTMCopyRam) self.flarebuffer.setSort(-100) # Camera that renders the flare buffer self.flarecamera = base.makeCamera(self.flarebuffer) #self.flarecamera.reparentTo(base.cam) #self.flarecamera.setPos(-50,0,0) self.ortlens = OrthographicLens() self.ortlens.setFilmSize( 10, 10) # or whatever is appropriate for your scene self.ortlens.setNearFar(1, self.distance) self.flarecamera.node().setLens(self.ortlens) self.flarecamera.node().setCameraMask(GXMgr.MASK_GXM_HIDDEN) # Create a light for the flare self.sunlight = self.baseNode.attachNewNode( PointLight("Sun:Point Light")) self.sunlight.node().setColor(self.suncolor) self.sunlight.node().setAttenuation(Vec3(0.1, 0.04, 0.0)) # Load texture cards # Create a nodepath that'll hold the texture cards for the new lens-flare self.texcardNP = aspect2d.attachNewNode('Sun:flareNode1') self.texcardNP.attachNewNode('Sun:fakeHdr') self.texcardNP.attachNewNode('Sun:starburstNode') # Load a circle and assign it a color. This will be used to calculate # Flare occlusion self.starcard = loader.loadModel('../data/models/unitcircle.egg') self.starcard.reparentTo(self.baseNode) self.starcard.setColor(self.suncardcolor) self.starcard.setScale(1) #self.starcard.setTransparency(TransparencyAttrib.MAlpha) # This is necessary since a billboard always rotates the y-axis to the # target but we need the z-axis self.starcard.setP(-90) self.starcard.setBillboardPointEye(self.flarecamera, 0.0) # Don't let the main camera see the star card self.starcard.show(GXMgr.MASK_GXM_HIDDEN) self.starcard.hide(GXMgr.MASK_GXM_VISIBLE) #the models are really just texture cards create with egg-texture-cards # from the actual pictures self.hdr = loader.loadModel('../data/models/fx_flare.egg') self.hdr.reparentTo(self.texcardNP.find('**/Sun:fakeHdr')) # Flare specs self.starburst_0 = loader.loadModel( '../data/models/fx_starburst_01.egg') self.starburst_1 = loader.loadModel( '../data/models/fx_starburst_02.egg') self.starburst_2 = loader.loadModel( '../data/models/fx_starburst_03.egg') self.starburst_0.setPos(0.5, 0, 0.5) self.starburst_1.setPos(0.5, 0, 0.5) self.starburst_2.setPos(0.5, 0, 0.5) self.starburst_0.setScale(.2) self.starburst_1.setScale(.2) self.starburst_2.setScale(.2) self.starburst_0.reparentTo( self.texcardNP.find('**/Sun:starburstNode')) self.starburst_1.reparentTo( self.texcardNP.find('**/Sun:starburstNode')) self.starburst_2.reparentTo( self.texcardNP.find('**/Sun:starburstNode')) self.texcardNP.setTransparency(TransparencyAttrib.MAlpha) # Put the texture cards in the background bin self.texcardNP.setBin('background', 0) # The texture cards do not affect the depth buffer self.texcardNP.setDepthWrite(False) #attach a node to the screen middle, used for some math self.mid2d = aspect2d.attachNewNode('mid2d') #start the task that implements the lens-flare taskMgr.add(self._flareTask, 'Sun:flareTask') ## this function returns the aspect2d position of a light source, if it enters the cameras field of view def _get2D(self, nodePath): #get the position of the light source relative to the cam p3d = base.cam.getRelativePoint(nodePath, Point3(0, 0, 0)) p2d = Point2() #project the light source into the viewing plane and return 2d coordinates, if it is in the visible area(read: not behind the cam) if base.cam.node().getLens().project(p3d, p2d): return p2d return None def _getObscured(self, color): # This originally looked for the radius of the light but that caused # assertion errors. Now I use the radius of the hdr model. bounds = self.starcard.getBounds() #print ("bounds=%s rad=%s"%(bounds,bounds.getRadius())) if not bounds.isEmpty(): r = bounds.getRadius() # Setting the film size sets the field-of-view and the aspect ratio # Maybe this should be done with setAspectRation() and setFov() self.ortlens.setFilmSize(r * self.radius, r * self.radius) # Point the flarecamera at the sun so we can determine if anything # is obscurring the sun self.flarecamera.lookAt(self.baseNode) # Renders the next frame in all the registered windows, and flips # all of the frame buffers. This will populate flaretexture since # it's attached to the flarebuffer. # Save the rendered frame in flaredata base.graphicsEngine.renderFrame() self.flaretexture.store(self.flaredata) #print ("flaredata=%s | color=%s"%(self.flaredata.getXel(5,5), color)) # Initialize the obscured factor obscured = 100.0 color = VBase3D(color[0], color[1], color[2]) for x in xrange(0, 9): for y in xrange(0, 9): if color.almostEqual(self.flaredata.getXel(x, y), self.threshold): obscured -= 1.0 else: obscured = 0 return obscured def _flareTask(self, task): #going through the list of lightNodePaths #for index in xrange(0, len(self.lightNodes)): pos2d = self._get2D(self.sunlight) #if the light source is visible from the cam's point of view, # display the lens-flare if pos2d: #print ("Flare visible") # The the obscured factor obscured = self._getObscured(self.suncardcolor) # Scale it to [0,1] self.obscured = obscured / 100 ##print obscured # Length is the length of the vector that goes from the screen # middle to the pos of the light. The length gets smaller the # closer the light is to the screen middle, however, since # length is used to calculate the brightness of the effect we # actually need an inverse behaviour, since the brightness # will be greates when center of screen= pos of light length = math.sqrt(pos2d.getX() * pos2d.getX() + pos2d.getY() * pos2d.getY()) invLength = 1.0 - length * 2 # Subtract the obscured factor from the inverted distence and # we have a value that simulates the power of the flare #brightness flarePower = invLength - self.obscured #print("light pos=%s | length=%s"%(pos2d,length)) print("obs=%s | length=%s | inv=%s | pow=%s" % (self.obscured, length, invLength, flarePower)) # Clamp the flare power to some values if flarePower < 0 and self.obscured > 0: flarePower = 0.0 if flarePower < 0 and self.obscured <= 0: flarePower = 0.3 if flarePower > 1: flarePower = 1 print("flarepower=%s" % (flarePower)) # if self.obscured >= 0.8: self.texcardNP.find('**/Sun:starburstNode').hide() else: self.texcardNP.find('**/Sun:starburstNode').show() #drawing the lens-flare effect... r = self.suncolor.getX() g = self.suncolor.getY() b = self.suncolor.getZ() r = math.sqrt(r * r + length * length) * self.strength g = math.sqrt(g * g + length * length) * self.strength b = math.sqrt(b * b + length * length) * self.strength print("%s,%s,%s" % (r, g, b)) # if self.obscured > 0.19: a = self.obscured - 0.2 else: a = 0.4 - flarePower # if a < 0: a = 0 if a > 0.8: a = 0.8 # self.hdr.setColor(r, g, b, 0.8 - a) self.hdr.setR(90 * length) self.texcardNP.find('**/Sun:starburstNode').setColor( r, g, b, 0.5 + length) self.hdr.setPos(pos2d.getX(), 0, pos2d.getY()) self.hdr.setScale(8.5 + (5 * length)) vecMid = Vec2(self.mid2d.getX(), self.mid2d.getZ()) vec2d = Vec2(vecMid - pos2d) vec3d = Vec3(vec2d.getX(), 0, vec2d.getY()) self.starburst_0.setPos(self.hdr.getPos() - (vec3d * 10)) self.starburst_1.setPos(self.hdr.getPos() - (vec3d * 5)) self.starburst_2.setPos(self.hdr.getPos() - (vec3d * 10)) self.texcardNP.show() #print "a",a else: #hide the lens-flare effect for a light source, if it is not visible... self.texcardNP.hide() return Task.cont
class TexturePainter(DirectObject): def __init__(self): self.editTexture = None self.editModel = None self.texturePainterStatus = TEXTURE_PAINTER_STATUS_DISABLED self.paintColor = VBase4D(1,1,1,1) self.paintSize = 10 self.paintEffect = PNMBrush.BEBlend self.paintSmooth = True self.paintMode = TEXTUREPAINTER_FUNCTION_PAINT_POINT self.painter = None # --- creation and destroying of the whole editor --- def enableEditor(self): ''' create the editor change from disabled to enabled''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_DISABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_ENABLED self.__enableEditor() else: print "E: TexturePainter.enableEditor: not disabled", self.texturePainterStatus def disableEditor(self): ''' destroy the editor, automatically stop the editor and painting change from enabled to disabled''' # try stopping if more advanced mode #if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: # self.stopEditor() if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_ENABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_DISABLED self.__disableEditor() else: print "E: TexturePainter.disableEditor: not enabled", self.texturePainterStatus # --- def startEditor(self, editModel, editTexture, backgroundShader=MODEL_COLOR_SHADER): ''' prepare to paint change from enabled to initialized''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_ENABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_INITIALIZED self.__startEditor(editModel, editTexture, backgroundShader) else: print "E: TexturePainter.startEditor: not enabled", self.texturePainterStatus def stopEditor(self): ''' stop painting, automatically stop painting change from initialized to enabled''' #if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: # self.stopPaint() if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_ENABLED return self.__stopEditor() else: print "E: TexturePainter.startEditor: not initialized", self.texturePainterStatus """ # this is not externally callable # --- def startPaint(self): ''' start painting on the model change from initialized to running ''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_RUNNING self.__startPaint() else: print "E: TexturePainter.startPaint: not enabled", self.texturePainterStatus""" def stopPaint(self): ''' stop painting change from running to initialized ''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_RUNNING: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_INITIALIZED self.__stopPaint() else: print "E: TexturePainter.stopPaint: not running", self.texturePainterStatus # --- brush settings for painting --- ''' changing brush settings is possible all the time ''' def setBrushSettings(self, color, size, smooth, effect): #print "I: TexturePainter.setBrushSettings", color, size, smooth, effect self.paintColor = color self.paintSize = size self.paintEffect = effect self.paintSmooth = smooth if effect in [PNMBrush.BESet, PNMBrush.BEBlend, PNMBrush.BEDarken, PNMBrush.BELighten]: self.brush = PNMBrush.makeSpot(color, size, smooth, effect) #if self.paintModel: if self.painter: self.painter.setPen(self.brush) def getBrushSettings(self): return self.paintColor,self.paintSize,self.paintSmooth,self.paintEffect def setPaintMode(self, newMode): self.paintMode = newMode # clear last point if mode changed if newMode == TEXTUREPAINTER_FUNCTION_PAINT_POINT or \ newMode == TEXTUREPAINTER_FUNCTION_READ: self.lastPoint = None def getPaintMode(self): return self.paintMode def __enableEditor(self): ''' create the background rendering etc., but the model is not yet defined ''' print "I: TexturePainter.__enableEditor" # the buffer the model with the color texture is rendered into self.modelColorBuffer = None self.modelColorCam = None # the buffer the picked position color is rendered into self.colorPickerBuffer = None self.colorPickerCam = None # create the buffers self.__createBuffer() # when the window is resized, the background buffer etc must be updated. self.accept("window-event", self.__windowEvent) # some debugging stuff self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) def __disableEditor(self): print "I: TexturePainter.__disableEditor" self.__destroyBuffer() # ignore window-event and debug self.ignoreAll() def __windowEvent(self, win=None): ''' when the editor is enabled, update the buffers etc. when the window is resized ''' print "I: TexturePainter.windowEvent" # with a fixed backgroudn buffer size this is not needed anymore if False: #if self.texturePainterStatus != TEXTURE_PAINTER_STATUS_DISABLED: if self.modelColorBuffer: if WindowManager.activeWindow: # on window resize there seems to be never a active window win = WindowManager.activeWindow.win else: win = base.win if self.modelColorBuffer.getXSize() != win.getXSize() or self.modelColorBuffer.getYSize() != win.getYSize(): '''print " - window resized",\ self.modelColorBuffer.getXSize(),\ win.getXSize(),\ self.modelColorBuffer.getYSize(),\ win.getYSize()''' # if the buffer size doesnt match the window size (window has been resized) self.__destroyBuffer() self.__createBuffer() self.__updateModel() else: print "W: TexturePainter.__windowEvent: no buffer" self.__createBuffer() def __createBuffer(self): ''' create the buffer we render in the background into ''' print "I: TexturePainter.__createBuffer" # the window has been modified if WindowManager.activeWindow: # on window resize there seems to be never a active window win = WindowManager.activeWindow.win else: win = base.win # get the window size self.windowSizeX = win.getXSize() self.windowSizeY = win.getYSize() # create a buffer in which we render the model using a shader self.paintMap = Texture() # 1.5.4 cant handle non power of 2 buffers self.modelColorBuffer = createOffscreenBuffer(-3, TEXTUREPAINTER_BACKGROUND_BUFFER_RENDERSIZE[0], TEXTUREPAINTER_BACKGROUND_BUFFER_RENDERSIZE[1]) #self.windowSizeX, self.windowSizeY) self.modelColorBuffer.addRenderTexture(self.paintMap, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) self.modelColorCam = base.makeCamera(self.modelColorBuffer, lens=base.cam.node().getLens(), sort=1) # Create a small buffer for the shader program that will fetch the point from the texture made # by the self.modelColorBuffer self.colorPickerImage = PNMImage() self.colorPickerTex = Texture() self.colorPickerBuffer = base.win.makeTextureBuffer("color picker buffer", 2, 2, self.colorPickerTex, True) self.colorPickerScene = NodePath('color picker scene') self.colorPickerCam = base.makeCamera(self.colorPickerBuffer, lens=base.cam.node().getLens(), sort=2) self.colorPickerCam.reparentTo(self.colorPickerScene) self.colorPickerCam.setY(-2) cm = CardMaker('color picker scene card') cm.setFrameFullscreenQuad() pickerCard = self.colorPickerScene.attachNewNode(cm.generate()) loadPicker = NodePath(PandaNode('pointnode')) loadPicker.setShader(Shader.make(COLOR_PICKER_SHADER), 10001) # Feed the paintmap from the paintBuffer to the shader and initial mouse positions self.colorPickerScene.setShaderInput('paintmap', self.paintMap) self.colorPickerScene.setShaderInput('mousepos', 0, 0, 0, 1) self.colorPickerCam.node().setInitialState(loadPicker.getState()) def __destroyBuffer(self): print "I: TexturePainter.__destroyBuffer" if self.modelColorBuffer: # Destroy the buffer base.graphicsEngine.removeWindow(self.modelColorBuffer) self.modelColorBuffer = None # Remove the camera self.modelColorCam.removeNode() del self.modelColorCam self.colorPickerScene.removeNode() del self.colorPickerScene # remove cam self.colorPickerCam.removeNode() del self.colorPickerCam # Destroy the buffer base.graphicsEngine.removeWindow(self.colorPickerBuffer) self.colorPickerBuffer = None del self.colorPickerTex del self.colorPickerImage def __startEditor(self, editModel, editTexture, backgroundShader=MODEL_COLOR_SHADER): print "I: TexturePainter.__startEditor" # this is needed as on startup the editor may not have had a window etc. self.__windowEvent() if not editModel or not editTexture: print "W: TexturePainter.__startEditor: model or texture invalid", editModel, editTexture return False self.editModel = editModel self.editTexture = editTexture self.editImage = None self.backgroundShader = backgroundShader if type(self.editTexture) == Texture: # if the image to modify is a texture, create a pnmImage which we modify self.editImage = PNMImage() # copy the image from the texture to the working layer self.editTexture.store(self.editImage) else: self.editImage = self.editTexture # create the brush for painting self.painter = PNMPainter(self.editImage) self.setBrushSettings( *self.getBrushSettings() ) self.__updateModel() # start edit messenger.send(EVENT_TEXTUREPAINTER_STARTEDIT) for startEvent in TEXTUREPAINTER_START_PAINT_EVENTS: self.accept(startEvent, self.__startPaint) for stopEvent in TEXTUREPAINTER_STOP_PAINT_EVENTS: self.accept(stopEvent, self.__stopPaint) self.modelColorCam.node().copyLens(WindowManager.activeWindow.camera.node().getLens()) taskMgr.add(self.__paintTask, 'paintTask') #modelModificator.toggleEditmode(False) self.isPainting = False def __stopEditor(self): print "I: TexturePainter.__stopEditor" for startEvent in TEXTUREPAINTER_START_PAINT_EVENTS: self.ignore(startEvent) for stopEvent in TEXTUREPAINTER_STOP_PAINT_EVENTS: self.ignore(stopEvent) taskMgr.remove('paintTask') # stop edit end # must be reset before we loose the properties if self.editModel and self.editTexture and self.editImage: try: # hide the model from cam 2 self.editModel.hide(BitMask32.bit(1)) self.editModel = None except: print "E: TexturePainter.__stopEditor: the model has already been deleted" # stop edit messenger.send(EVENT_TEXTUREPAINTER_STOPEDIT) self.editImage = None self.editTexture = None self.painter = None self.brush = None #modelModificator.toggleEditmode(True) def __updateModel(self): if self.editModel: # create a image with the same size of the texture textureSize = (self.editTexture.getXSize(), self.editTexture.getYSize()) # create a dummy node, where we setup the parameters for the background rendering loadPaintNode = NodePath(PandaNode('paintnode')) loadPaintNode.setShader(Shader.make(self.backgroundShader), 10001) loadPaintNode.setShaderInput('texsize', textureSize[0], textureSize[1], 0, 0) # copy the state onto the camera self.modelColorCam.node().setInitialState(loadPaintNode.getState()) # the camera gets a special bitmask, to show/hide models from it self.modelColorCam.node().setCameraMask(BitMask32.bit(1)) if False: # doesnt work, but would be nicer (not messing with the default render state) hiddenNode = NodePath(PandaNode('hiddennode')) hiddenNode.hide(BitMask32.bit(1)) showTroughNode = NodePath(PandaNode('showtroughnode')) showTroughNode.showThrough(BitMask32.bit(1)) self.modelColorCam.node().setTagStateKey('show-on-backrender-cam') self.modelColorCam.node().setTagState('False', hiddenNode.getState()) self.modelColorCam.node().setTagState('True', showTroughNode.getState()) render.setTag('show-on-backrender-cam', 'False') self.editModel.setTag('show-on-backrender-cam', 'True') else: # make only the model visible to the background camera render.hide(BitMask32.bit(1)) self.editModel.showThrough(BitMask32.bit(1)) # --- start the paint tasks --- def __startPaint(self): self.isPainting = True def __stopPaint(self): self.isPainting = False # --- modification tasks --- def __textureUpdateTask(self, task=None): ''' modify the texture using the edited image ''' if type(self.editTexture) == Texture: self.editTexture.load(self.editImage) if task: # task may be None return task.again def __paintTask(self, task): #print "I: TexturePainter.__paintTask:" if not WindowManager.activeWindow or not WindowManager.activeWindow.mouseWatcherNode.hasMouse(): '''print " - abort:", WindowManager.activeWindow if WindowManager.activeWindow: print " - mouse:", WindowManager.activeWindow.mouseWatcherNode.hasMouse()''' return task.cont # update the camera according to the active camera #self.modelColorCam.setMat(render, WindowManager.activeWindow.camera.getMat(render)) mpos = base.mouseWatcherNode.getMouse() x_ratio = min( max( ((mpos.getX()+1)/2), 0), 1) y_ratio = min( max( ((mpos.getY()+1)/2), 0), 1) mx = int(x_ratio*self.windowSizeX) my = self.windowSizeY - int(y_ratio*self.windowSizeY) self.colorPickerScene.setShaderInput('mousepos', x_ratio, y_ratio, 0, 1) if self.colorPickerTex.hasRamImage(): self.colorPickerTex.store(self.colorPickerImage) # get the color below the mousepick from the rendered frame r = self.colorPickerImage.getRedVal(0,0) g = self.colorPickerImage.getGreenVal(0,0) b = self.colorPickerImage.getBlueVal(0,0) # calculate uv-texture position from the color x = r + ((b%16)*256) y = g + ((b//16)*256) if self.isPainting: self.__paintPixel(x,y) self.__textureUpdateTask() else: # this might happen if no frame has been rendered yet since creation of the texture print "W: TexturePainter.__paintTask: colorPickerTex.hasRamMipmapImage() =", self.colorPickerTex.hasRamImage() return task.cont def __paintPixel(self, x, y): ''' paint at x/y with the defined settings ''' imageMaxX = self.editImage.getXSize() imageMaxY = self.editImage.getYSize() def inImage(x,y): ''' is the given x/y position within the image ''' return ((imageMaxX > x >= 0) and (imageMaxY > y >= 0)) # how smooth should be painted if self.paintSmooth: # a smooth brush hardness = 1.0 else: # a hard brush hardness = 0.1 hardness = min(1.0, max(0.05, hardness)) # the paint radius radius = int(round(self.paintSize/2.0)) radiusSquare = float(radius*radius) # a function to get the brush color/strength, depending on the radius def getBrushColor(diffPosX, diffPosY): distance = diffPosX**2 + diffPosY**2 brushStrength = (1 - (min(distance, radiusSquare) / radiusSquare)) / hardness return min(1.0, max(0.0, brushStrength)) if inImage(x,y): if self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_POINT: if self.paintEffect in [PNMBrush.BESet, PNMBrush.BEBlend, PNMBrush.BEDarken, PNMBrush.BELighten]: # render a spot into the texture self.painter.drawPoint(x, y) elif self.paintEffect in [TEXTUREPAINTER_BRUSH_FLATTEN, TEXTUREPAINTER_BRUSH_SMOOTH, TEXTUREPAINTER_BRUSH_RANDOMIZE]: if self.paintEffect == TEXTUREPAINTER_BRUSH_SMOOTH: # calculate average values data = dict() smoothRadius = 2 for dx in xrange(-radius, radius+1): for dy in xrange(-radius, radius+1): if inImage(x+dx,y+dy): average = VBase4D(0) dividor = 0 for px in xrange(-smoothRadius,smoothRadius+1): for py in xrange(-smoothRadius,smoothRadius+1): if inImage(x+dx+px,y+dy+py): average += self.editImage.getXelA(x+dx+px,y+dy+py) dividor += 1 average /= float(dividor) data[(x+dx,y+dy)] = average # save to image for (px,py), newValue in data.items(): currentValue = self.editImage.getXelA(px,py) diffValue = currentValue - newValue dx = px - x dy = py - y multiplier = getBrushColor(dx, dy) print dx, dy, multiplier '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' '''r = currentValue.getX() * (1-multiplier*self.paintColor.getX()) + diffValue.getX() * multiplier*self.paintColor.getX() g = currentValue.getY() * (1-multiplier*self.paintColor.getY()) + diffValue.getY() * multiplier*self.paintColor.getY() b = currentValue.getZ() * (1-multiplier*self.paintColor.getZ()) + diffValue.getZ() * multiplier*self.paintColor.getZ() a = currentValue.getW() * (1-multiplier*self.paintColor.getW()) + diffValue.getW() * multiplier*self.paintColor.getW()''' r = currentValue.getX() - multiplier * diffValue.getX() g = currentValue.getY() - multiplier * diffValue.getY() b = currentValue.getZ() - multiplier * diffValue.getZ() a = currentValue.getW() - multiplier * diffValue.getW() if self.editImage.hasAlpha(): self.editImage.setXelA(px,py,VBase4D(r,g,b,a)) else: self.editImage.setXel(px,py,VBase3D(r,g,b)) #self.editImage.setXelA(x,y,value) if self.paintEffect == TEXTUREPAINTER_BRUSH_FLATTEN: dividor = 0 average = VBase4D(0) for dx in xrange(-radius, radius+1): for dy in xrange(-radius, radius+1): if inImage(x+dx,y+dy): multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' dividor += multiplier average += self.editImage.getXelA(x+dx,y+dy) * multiplier average /= dividor for dx in xrange(-radius, radius+1): for dy in xrange(-radius, radius+1): if inImage(x+dx,y+dy): multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' currentValue = self.editImage.getXelA(x+dx,y+dy) r = currentValue.getX() * (1-multiplier*self.paintColor.getX()) + average.getX() * multiplier*self.paintColor.getX() g = currentValue.getY() * (1-multiplier*self.paintColor.getY()) + average.getY() * multiplier*self.paintColor.getY() b = currentValue.getZ() * (1-multiplier*self.paintColor.getZ()) + average.getZ() * multiplier*self.paintColor.getZ() a = currentValue.getW() * (1-multiplier*self.paintColor.getW()) + average.getW() * multiplier*self.paintColor.getW() if self.editImage.hasAlpha(): self.editImage.setXelA(x+dx,y+dy,VBase4D(r,g,b,a)) else: self.editImage.setXel(x+dx,y+dy,VBase3D(r,g,b)) elif self.paintEffect == TEXTUREPAINTER_BRUSH_RANDOMIZE: for dx in xrange(-radius, radius+1): for dy in xrange(-radius, radius+1): if inImage(x+dx,y+dy): r = VBase4D(random.random()*self.paintColor.getX()-self.paintColor.getX()/2., random.random()*self.paintColor.getY()-self.paintColor.getY()/2., random.random()*self.paintColor.getZ()-self.paintColor.getZ()/2., random.random()*self.paintColor.getW()-self.paintColor.getW()/2.) multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' currentValue = self.editImage.getXelA(x+dx,y+dy) self.editImage.setXelA(x+dx,y+dy,currentValue+r*multiplier) elif self.paintMode == TEXTUREPAINTER_FUNCTION_READ: if inImage(x,y): col = self.editImage.getXelA(x,y) if self.editImage.hasAlpha(): self.paintColor = VBase4D(col[0], col[1], col[2], col[3]) else: self.paintColor = VBase4D(col[0], col[1], col[2], 1.0) messenger.send(EVENT_TEXTUREPAINTER_BRUSHCHANGED) elif self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_LINE: if self.lastPoint != None: self.painter.drawLine(x, y, self.lastPoint[0], self.lastPoint[1]) elif self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_RECTANGLE: if self.lastPoint != None: self.painter.drawRectangle(x, y, self.lastPoint[0], self.lastPoint[1]) self.lastPoint = (x,y)
class HtmlView(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("HtmlView") useHalfTexture = base.config.GetBool("news-half-texture", 0) def __init__(self, parent=aspect2d): """Properly initialize ourself.""" #AwWebViewListener.AwWebViewListener.__init__(self) self.parent = parent self.mx = 0 self.my = 0 self.htmlFile = "index.html" self.transparency = False # this is important looks weird if it's true global GlobalWebcore if GlobalWebcore: # we get a C++ crash if we construct webcore a second time pass else: GlobalWebcore = AwWebCore(AwWebCore.LOGVERBOSE, True, AwWebCore.PFBGRA) GlobalWebcore.setBaseDirectory('.') for errResponse in xrange(400, 600): GlobalWebcore.setCustomResponsePage(errResponse, "error.html") self.webView = GlobalWebcore.createWebView(WEB_WIDTH, WEB_HEIGHT, self.transparency, False, 70) #self.webView.setListener(self) #self.webView.setCallback("requestFPS"); frameName = '' inGameNewsUrl = self.getInGameNewsUrl() #self.webView.loadURL2(inGameNewsUrl) self.imgBuffer = array.array('B') for i in xrange(WEB_WIDTH * WEB_HEIGHT): self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(255) if self.useHalfTexture: self.leftBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(255) self.rightBuffer = array.array('B') for i in xrange(WEB_HALF_WIDTH * WEB_HEIGHT): self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(255) self.setupTexture() if self.useHalfTexture: self.setupHalfTextures() #self.interval = LerpHprInterval(self.quad, 2, Vec3(360, 0, 0), Vec3(0, 0, 0)) #self.accept("escape", sys.exit, [0]) #self.accept("w", self.writeTex) self.accept("mouse1", self.mouseDown, [AwWebView.LEFTMOUSEBTN]) self.accept("mouse3", self.mouseDown, [AwWebView.RIGHTMOUSEBTN]) self.accept("mouse1-up", self.mouseUp, [AwWebView.LEFTMOUSEBTN]) self.accept("mouse3-up", self.mouseUp, [AwWebView.RIGHTMOUSEBTN]) #self.accept("f1", self.toggleRotation) #self.accept("f2", self.toggleTransparency) #self.accept("f3", self.reload) #self.accept("f4", self.zoomIn) #self.accept("f5", self.zoomOut) #taskMgr.doMethodLater(1.0, self.update, 'HtmlViewUpdateTask') # we get a problem if a mid-frame hearbeat fires of this task in conjunction with igLoop #taskMgr.add(self.update, 'HtmlViewUpdateTask', priority = 51) #taskMgr.add(self.update, 'HtmlViewUpdateTask') #base.newsFrame = self def getInGameNewsUrl(self): """Get the appropriate URL to use if we are in test, qa, or live.""" # First if all else fails, we hard code the live news url result = base.config.GetString( "fallback-news-url", "http://cdn.toontown.disney.go.com/toontown/en/gamenews/") # next check if we have an override, say they want to url to point to a file in their harddisk override = base.config.GetString("in-game-news-url", "") if override: self.notify.info( "got an override url, using %s for in a game news" % override) result = override else: try: launcherUrl = base.launcher.getValue("GAME_IN_GAME_NEWS_URL", "") if launcherUrl: result = launcherUrl self.notify.info( "got GAME_IN_GAME_NEWS_URL from launcher using %s" % result) else: self.notify.info( "blank GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) except: self.notify.warning( "got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) return result def setupTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) bottomRightX = (WEB_WIDTH_PIXELS) / float(WEB_WIDTH + 1) bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1) #cm.setUvRange(Point2(0,0), Point2(bottomRightX, bottomRightY)) cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1)) card = cm.generate() self.quad = NodePath(card) self.quad.reparentTo(self.parent) self.guiTex = Texture("guiTex") self.guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.guiTex.setMinfilter(Texture.FTLinear) self.guiTex.setKeepRamImage(True) self.guiTex.makeRamImage() self.guiTex.setWrapU(Texture.WMRepeat) self.guiTex.setWrapV(Texture.WMRepeat) ts = TextureStage('webTS') self.quad.setTexture(ts, self.guiTex) self.quad.setTexScale(ts, 1.0, -1.0) self.quad.setTransparency(0) self.quad.setTwoSided(True) self.quad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 self.calcMouseLimits() def setupHalfTextures(self): self.setupLeftTexture() self.setupRightTexture() self.fullPnmImage = PNMImage(WEB_WIDTH, WEB_HEIGHT, 4) self.leftPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) self.rightPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) def setupLeftTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(-htmlWidth / 2.0, 0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.leftQuad = NodePath(card) self.leftQuad.reparentTo(self.parent) self.leftGuiTex = Texture("guiTex") self.leftGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.leftGuiTex.setKeepRamImage(True) self.leftGuiTex.makeRamImage() self.leftGuiTex.setWrapU(Texture.WMClamp) self.leftGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('leftWebTS') self.leftQuad.setTexture(ts, self.leftGuiTex) self.leftQuad.setTexScale(ts, 1.0, -1.0) self.leftQuad.setTransparency(0) self.leftQuad.setTwoSided(True) self.leftQuad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 def setupRightTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.rightQuad = NodePath(card) self.rightQuad.reparentTo(self.parent) self.rightGuiTex = Texture("guiTex") self.rightGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.rightGuiTex.setKeepRamImage(True) self.rightGuiTex.makeRamImage() self.rightGuiTex.setWrapU(Texture.WMClamp) self.rightGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('rightWebTS') self.rightQuad.setTexture(ts, self.rightGuiTex) self.rightQuad.setTexScale(ts, 1.0, -1.0) self.rightQuad.setTransparency(0) self.rightQuad.setTwoSided(True) self.rightQuad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 def calcMouseLimits(self): ll = Point3() ur = Point3() self.quad.calcTightBounds(ll, ur) self.notify.debug("ll=%s ur=%s" % (ll, ur)) # we need to get our relative position to aspect2d, since shtiker books is shifted offset = self.quad.getPos(aspect2d) self.notify.debug("offset = %s " % offset) ll.setZ(ll.getZ() + offset.getZ()) ur.setZ(ur.getZ() + offset.getZ()) self.notify.debug("new LL=%s, UR=%s" % (ll, ur)) relPointll = self.quad.getRelativePoint(aspect2d, ll) self.notify.debug("relPoint = %s" % relPointll) self.mouseLL = (aspect2d.getScale()[0] * ll[0], aspect2d.getScale()[2] * ll[2]) self.mouseUR = (aspect2d.getScale()[0] * ur[0], aspect2d.getScale()[2] * ur[2]) self.notify.debug("original mouseLL=%s, mouseUR=%s" % (self.mouseLL, self.mouseUR)) def writeTex(self, filename="guiText.png"): self.notify.debug("writing texture") self.guiTex.generateRamMipmapImages() self.guiTex.write(filename) def toggleRotation(self): if self.interval.isPlaying(): self.interval.finish() else: self.interval.loop() def mouseDown(self, button): messenger.send('wakeup') self.webView.injectMouseDown(button) def mouseUp(self, button): self.webView.injectMouseUp(button) def reload(self): pass #self.webView.loadFile(self.htmlFile, '') def zoomIn(self): self.webView.zoomIn() def zoomOut(self): self.webView.zoomOut() def toggleTransparency(self): self.transparency = not self.transparency self.webView.setTransparent(self.transparency) def update(self, task): global GlobalWebcore if base.mouseWatcherNode.hasMouse(): x, y = self._translateRelativeCoordinates( base.mouseWatcherNode.getMouseX(), base.mouseWatcherNode.getMouseY()) #self.notify.debug('got mouse move %d %d' % (x,y)) #self.webView.injectMouseMove(x, y) if (self.mx - x) != 0 or (self.my - y) != 0: self.webView.injectMouseMove(x, y) #self.notify.debug('injecting mouse move %d %d' % (x,y)) self.mx, self.my = x, y if self.webView.isDirty(): #self.notify.debug("webview is dirty") self.webView.render(self.imgBuffer.buffer_info()[0], WEB_WIDTH * 4, 4) #Texture.setTexturesPower2(AutoTextureScale.ATSUp) Texture.setTexturesPower2(2) #self.notify.debug("about to modify ram image") textureBuffer = self.guiTex.modifyRamImage() #import pdb; pdb.set_trace() #self.notify.debug("about to call textureBuffer.setData") textureBuffer.setData(self.imgBuffer.tostring()) #self.notify.debug("done calling setData") if self.useHalfTexture: # TODO check with DRose, this feels inefficient self.guiTex.store(self.fullPnmImage) self.leftPnmImage.copySubImage(self.fullPnmImage, 0, 0, 0, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.rightPnmImage.copySubImage(self.fullPnmImage, 0, 0, WEB_HALF_WIDTH, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.leftGuiTex.load(self.leftPnmImage) self.rightGuiTex.load(self.rightPnmImage) self.quad.hide() #Texture.setTexturesPower2(AutoTextureScale.ATSDown) Texture.setTexturesPower2(1) GlobalWebcore.update() return Task.cont def _translateRelativeCoordinates(self, x, y): sx = int((x - self.mouseLL[0]) / (self.mouseUR[0] - self.mouseLL[0]) * WEB_WIDTH_PIXELS) sy = WEB_HEIGHT_PIXELS - int( (y - self.mouseLL[1]) / (self.mouseUR[1] - self.mouseLL[1]) * WEB_HEIGHT_PIXELS) return sx, sy def unload(self): """Clean up everything, especially the awesomium bits.""" self.ignoreAll() self.webView.destroy() self.webView = None #global GlobalWebcore #GlobalWebcore = None pass # --------------------[ WebViewListener implementation ]-------------------------- def onCallback(self, name, args): assert self.notify.debugStateCall(self) if name == "requestFPS": #self.webView.setProperty( "fps", JSValue("%.1f" % (1.0 / globalClock.getDt())) ) #self.webView.executeJavascript("updateFPS()", "") pass def onBeginNavigation(self, url, frameName): assert self.notify.debugStateCall(self) pass def onBeginLoading(self, url, frameName, statusCode, mimeType): assert self.notify.debugStateCall(self) pass def onFinishLoading(self): assert self.notify.debugStateCall(self) self.notify.debug("finished loading") pass def onReceiveTitle(self, title, frameName): assert self.notify.debugStateCall(self) pass def onChangeTooltip(self, tooltip): assert self.notify.debugStateCall(self) pass def onChangeCursor(self, cursor): assert self.notify.debugStateCall(self) pass def onChangeKeyboardFocus(self, isFocused): assert self.notify.debugStateCall(self) pass def onChangeTargetURL(self, url): assert self.notify.debugStateCall(self) pass
class GXOStar(GXOBase): def __init__(self, parent=render, pos=Vec3(50,0,0)): GXOBase.__init__(self, parent, pos) self._initializeFlare() def _initializeFlare(self): # Parameters self.distance = 130000.0 self.threshold = 0.3 self.radius = 0.8 self.strength = 1.0 self.suncolor = Vec4( 1, 1, 1, 1 ) self.suncardcolor = Vec4( 1, 1, 0, 0 ) # Initialize some values self.obscured = 0.0 # flaredata will hold the rendered image self.flaredata = PNMImage() # flaretexture will store the rendered buffer self.flaretexture = Texture() # Create a 10x10 texture buffer for the flare self.flarebuffer = base.win.makeTextureBuffer("Flare Buffer", 10, 10) # Attach the texture to the buffer self.flarebuffer.addRenderTexture(self.flaretexture, GraphicsOutput.RTMCopyRam) self.flarebuffer.setSort(-100) # Camera that renders the flare buffer self.flarecamera = base.makeCamera(self.flarebuffer) #self.flarecamera.reparentTo(base.cam) #self.flarecamera.setPos(-50,0,0) self.ortlens = OrthographicLens() self.ortlens.setFilmSize(10, 10) # or whatever is appropriate for your scene self.ortlens.setNearFar(1,self.distance) self.flarecamera.node().setLens(self.ortlens) self.flarecamera.node().setCameraMask(GXMgr.MASK_GXM_HIDDEN) # Create a light for the flare self.sunlight = self.baseNode.attachNewNode(PointLight("Sun:Point Light")) self.sunlight.node().setColor(self.suncolor) self.sunlight.node().setAttenuation(Vec3( 0.1, 0.04, 0.0 )) # Load texture cards # Create a nodepath that'll hold the texture cards for the new lens-flare self.texcardNP = aspect2d.attachNewNode('Sun:flareNode1') self.texcardNP.attachNewNode('Sun:fakeHdr') self.texcardNP.attachNewNode('Sun:starburstNode') # Load a circle and assign it a color. This will be used to calculate # Flare occlusion self.starcard = loader.loadModel('../data/models/unitcircle.egg') self.starcard.reparentTo(self.baseNode) self.starcard.setColor(self.suncardcolor) self.starcard.setScale(1) #self.starcard.setTransparency(TransparencyAttrib.MAlpha) # This is necessary since a billboard always rotates the y-axis to the # target but we need the z-axis self.starcard.setP(-90) self.starcard.setBillboardPointEye(self.flarecamera, 0.0) # Don't let the main camera see the star card self.starcard.show(GXMgr.MASK_GXM_HIDDEN) self.starcard.hide(GXMgr.MASK_GXM_VISIBLE) #the models are really just texture cards create with egg-texture-cards # from the actual pictures self.hdr = loader.loadModel('../data/models/fx_flare.egg') self.hdr.reparentTo(self.texcardNP.find('**/Sun:fakeHdr')) # Flare specs self.starburst_0 = loader.loadModel('../data/models/fx_starburst_01.egg') self.starburst_1 = loader.loadModel('../data/models/fx_starburst_02.egg') self.starburst_2 = loader.loadModel('../data/models/fx_starburst_03.egg') self.starburst_0.setPos(0.5,0,0.5) self.starburst_1.setPos(0.5,0,0.5) self.starburst_2.setPos(0.5,0,0.5) self.starburst_0.setScale(.2) self.starburst_1.setScale(.2) self.starburst_2.setScale(.2) self.starburst_0.reparentTo(self.texcardNP.find('**/Sun:starburstNode')) self.starburst_1.reparentTo(self.texcardNP.find('**/Sun:starburstNode')) self.starburst_2.reparentTo(self.texcardNP.find('**/Sun:starburstNode')) self.texcardNP.setTransparency(TransparencyAttrib.MAlpha) # Put the texture cards in the background bin self.texcardNP.setBin('background', 0) # The texture cards do not affect the depth buffer self.texcardNP.setDepthWrite(False) #attach a node to the screen middle, used for some math self.mid2d = aspect2d.attachNewNode('mid2d') #start the task that implements the lens-flare taskMgr.add(self._flareTask, 'Sun:flareTask') ## this function returns the aspect2d position of a light source, if it enters the cameras field of view def _get2D(self, nodePath): #get the position of the light source relative to the cam p3d = base.cam.getRelativePoint(nodePath, Point3(0,0,0)) p2d = Point2() #project the light source into the viewing plane and return 2d coordinates, if it is in the visible area(read: not behind the cam) if base.cam.node().getLens().project(p3d, p2d): return p2d return None def _getObscured(self, color): # This originally looked for the radius of the light but that caused # assertion errors. Now I use the radius of the hdr model. bounds = self.starcard.getBounds() #print ("bounds=%s rad=%s"%(bounds,bounds.getRadius())) if not bounds.isEmpty(): r = bounds.getRadius() # Setting the film size sets the field-of-view and the aspect ratio # Maybe this should be done with setAspectRation() and setFov() self.ortlens.setFilmSize(r * self.radius, r * self.radius) # Point the flarecamera at the sun so we can determine if anything # is obscurring the sun self.flarecamera.lookAt(self.baseNode) # Renders the next frame in all the registered windows, and flips # all of the frame buffers. This will populate flaretexture since # it's attached to the flarebuffer. # Save the rendered frame in flaredata base.graphicsEngine.renderFrame() self.flaretexture.store(self.flaredata) #print ("flaredata=%s | color=%s"%(self.flaredata.getXel(5,5), color)) # Initialize the obscured factor obscured = 100.0 color = VBase3D(color[0],color[1],color[2]) for x in xrange(0,9): for y in xrange(0,9): if color.almostEqual(self.flaredata.getXel(x,y), self.threshold): obscured -= 1.0 else: obscured = 0 return obscured def _flareTask(self, task): #going through the list of lightNodePaths #for index in xrange(0, len(self.lightNodes)): pos2d = self._get2D(self.sunlight) #if the light source is visible from the cam's point of view, # display the lens-flare if pos2d: #print ("Flare visible") # The the obscured factor obscured = self._getObscured(self.suncardcolor) # Scale it to [0,1] self.obscured = obscured/100 ##print obscured # Length is the length of the vector that goes from the screen # middle to the pos of the light. The length gets smaller the # closer the light is to the screen middle, however, since # length is used to calculate the brightness of the effect we # actually need an inverse behaviour, since the brightness # will be greates when center of screen= pos of light length = math.sqrt(pos2d.getX()*pos2d.getX()+pos2d.getY()*pos2d.getY()) invLength= 1.0-length*2 # Subtract the obscured factor from the inverted distence and # we have a value that simulates the power of the flare #brightness flarePower=invLength-self.obscured #print("light pos=%s | length=%s"%(pos2d,length)) print("obs=%s | length=%s | inv=%s | pow=%s"%(self.obscured,length,invLength,flarePower)) # Clamp the flare power to some values if flarePower < 0 and self.obscured > 0: flarePower = 0.0 if flarePower < 0 and self.obscured <= 0: flarePower = 0.3 if flarePower > 1 : flarePower = 1 print("flarepower=%s"%(flarePower)) # if self.obscured >= 0.8: self.texcardNP.find('**/Sun:starburstNode').hide() else: self.texcardNP.find('**/Sun:starburstNode').show() #drawing the lens-flare effect... r= self.suncolor.getX() g= self.suncolor.getY() b= self.suncolor.getZ() r = math.sqrt(r*r+length*length) * self.strength g = math.sqrt(g*g+length*length) * self.strength b = math.sqrt(b*b+length*length) * self.strength print("%s,%s,%s"%(r,g,b)) # if self.obscured > 0.19: a = self.obscured - 0.2 else: a = 0.4 - flarePower # if a < 0 : a = 0 if a > 0.8 : a = 0.8 # self.hdr.setColor(r,g,b,0.8-a) self.hdr.setR(90*length) self.texcardNP.find('**/Sun:starburstNode').setColor(r,g,b,0.5+length) self.hdr.setPos(pos2d.getX(),0,pos2d.getY()) self.hdr.setScale(8.5+(5*length)) vecMid = Vec2(self.mid2d.getX(), self.mid2d.getZ()) vec2d = Vec2(vecMid-pos2d) vec3d = Vec3(vec2d.getX(), 0, vec2d.getY()) self.starburst_0.setPos(self.hdr.getPos()-(vec3d*10)) self.starburst_1.setPos(self.hdr.getPos()-(vec3d*5)) self.starburst_2.setPos(self.hdr.getPos()-(vec3d*10)) self.texcardNP.show() #print "a",a else: #hide the lens-flare effect for a light source, if it is not visible... self.texcardNP.hide() return Task.cont
class TexturePainter(DirectObject): def __init__(self): self.editTexture = None self.editModel = None self.texturePainterStatus = TEXTURE_PAINTER_STATUS_DISABLED self.paintColor = VBase4D(1, 1, 1, 1) self.paintSize = 10 self.paintEffect = PNMBrush.BEBlend self.paintSmooth = True self.paintMode = TEXTUREPAINTER_FUNCTION_PAINT_POINT self.painter = None # --- creation and destroying of the whole editor --- def enableEditor(self): ''' create the editor change from disabled to enabled''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_DISABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_ENABLED self.__enableEditor() else: print "E: TexturePainter.enableEditor: not disabled", self.texturePainterStatus def disableEditor(self): ''' destroy the editor, automatically stop the editor and painting change from enabled to disabled''' # try stopping if more advanced mode #if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: # self.stopEditor() if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_ENABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_DISABLED self.__disableEditor() else: print "E: TexturePainter.disableEditor: not enabled", self.texturePainterStatus # --- def startEditor(self, editModel, editTexture, backgroundShader=MODEL_COLOR_SHADER): ''' prepare to paint change from enabled to initialized''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_ENABLED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_INITIALIZED self.__startEditor(editModel, editTexture, backgroundShader) else: print "E: TexturePainter.startEditor: not enabled", self.texturePainterStatus def stopEditor(self): ''' stop painting, automatically stop painting change from initialized to enabled''' #if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: # self.stopPaint() if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_ENABLED return self.__stopEditor() else: print "E: TexturePainter.startEditor: not initialized", self.texturePainterStatus """ # this is not externally callable # --- def startPaint(self): ''' start painting on the model change from initialized to running ''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_INITIALIZED: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_RUNNING self.__startPaint() else: print "E: TexturePainter.startPaint: not enabled", self.texturePainterStatus""" def stopPaint(self): ''' stop painting change from running to initialized ''' if self.texturePainterStatus == TEXTURE_PAINTER_STATUS_RUNNING: self.texturePainterStatus = TEXTURE_PAINTER_STATUS_INITIALIZED self.__stopPaint() else: print "E: TexturePainter.stopPaint: not running", self.texturePainterStatus # --- brush settings for painting --- ''' changing brush settings is possible all the time ''' def setBrushSettings(self, color, size, smooth, effect): #print "I: TexturePainter.setBrushSettings", color, size, smooth, effect self.paintColor = color self.paintSize = size self.paintEffect = effect self.paintSmooth = smooth if effect in [ PNMBrush.BESet, PNMBrush.BEBlend, PNMBrush.BEDarken, PNMBrush.BELighten ]: self.brush = PNMBrush.makeSpot(color, size, smooth, effect) #if self.paintModel: if self.painter: self.painter.setPen(self.brush) def getBrushSettings(self): return self.paintColor, self.paintSize, self.paintSmooth, self.paintEffect def setPaintMode(self, newMode): self.paintMode = newMode # clear last point if mode changed if newMode == TEXTUREPAINTER_FUNCTION_PAINT_POINT or \ newMode == TEXTUREPAINTER_FUNCTION_READ: self.lastPoint = None def getPaintMode(self): return self.paintMode def __enableEditor(self): ''' create the background rendering etc., but the model is not yet defined ''' print "I: TexturePainter.__enableEditor" # the buffer the model with the color texture is rendered into self.modelColorBuffer = None self.modelColorCam = None # the buffer the picked position color is rendered into self.colorPickerBuffer = None self.colorPickerCam = None # create the buffers self.__createBuffer() # when the window is resized, the background buffer etc must be updated. self.accept("window-event", self.__windowEvent) # some debugging stuff self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) def __disableEditor(self): print "I: TexturePainter.__disableEditor" self.__destroyBuffer() # ignore window-event and debug self.ignoreAll() def __windowEvent(self, win=None): ''' when the editor is enabled, update the buffers etc. when the window is resized ''' print "I: TexturePainter.windowEvent" # with a fixed backgroudn buffer size this is not needed anymore if False: #if self.texturePainterStatus != TEXTURE_PAINTER_STATUS_DISABLED: if self.modelColorBuffer: if WindowManager.activeWindow: # on window resize there seems to be never a active window win = WindowManager.activeWindow.win else: win = base.win if self.modelColorBuffer.getXSize() != win.getXSize( ) or self.modelColorBuffer.getYSize() != win.getYSize(): '''print " - window resized",\ self.modelColorBuffer.getXSize(),\ win.getXSize(),\ self.modelColorBuffer.getYSize(),\ win.getYSize()''' # if the buffer size doesnt match the window size (window has been resized) self.__destroyBuffer() self.__createBuffer() self.__updateModel() else: print "W: TexturePainter.__windowEvent: no buffer" self.__createBuffer() def __createBuffer(self): ''' create the buffer we render in the background into ''' print "I: TexturePainter.__createBuffer" # the window has been modified if WindowManager.activeWindow: # on window resize there seems to be never a active window win = WindowManager.activeWindow.win else: win = base.win # get the window size self.windowSizeX = win.getXSize() self.windowSizeY = win.getYSize() # create a buffer in which we render the model using a shader self.paintMap = Texture() # 1.5.4 cant handle non power of 2 buffers self.modelColorBuffer = createOffscreenBuffer( -3, TEXTUREPAINTER_BACKGROUND_BUFFER_RENDERSIZE[0], TEXTUREPAINTER_BACKGROUND_BUFFER_RENDERSIZE[1] ) #self.windowSizeX, self.windowSizeY) self.modelColorBuffer.addRenderTexture(self.paintMap, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) self.modelColorCam = base.makeCamera(self.modelColorBuffer, lens=base.cam.node().getLens(), sort=1) # Create a small buffer for the shader program that will fetch the point from the texture made # by the self.modelColorBuffer self.colorPickerImage = PNMImage() self.colorPickerTex = Texture() self.colorPickerBuffer = base.win.makeTextureBuffer( "color picker buffer", 2, 2, self.colorPickerTex, True) self.colorPickerScene = NodePath('color picker scene') self.colorPickerCam = base.makeCamera(self.colorPickerBuffer, lens=base.cam.node().getLens(), sort=2) self.colorPickerCam.reparentTo(self.colorPickerScene) self.colorPickerCam.setY(-2) cm = CardMaker('color picker scene card') cm.setFrameFullscreenQuad() pickerCard = self.colorPickerScene.attachNewNode(cm.generate()) loadPicker = NodePath(PandaNode('pointnode')) loadPicker.setShader(Shader.make(COLOR_PICKER_SHADER), 10001) # Feed the paintmap from the paintBuffer to the shader and initial mouse positions self.colorPickerScene.setShaderInput('paintmap', self.paintMap) self.colorPickerScene.setShaderInput('mousepos', 0, 0, 0, 1) self.colorPickerCam.node().setInitialState(loadPicker.getState()) def __destroyBuffer(self): print "I: TexturePainter.__destroyBuffer" if self.modelColorBuffer: # Destroy the buffer base.graphicsEngine.removeWindow(self.modelColorBuffer) self.modelColorBuffer = None # Remove the camera self.modelColorCam.removeNode() del self.modelColorCam self.colorPickerScene.removeNode() del self.colorPickerScene # remove cam self.colorPickerCam.removeNode() del self.colorPickerCam # Destroy the buffer base.graphicsEngine.removeWindow(self.colorPickerBuffer) self.colorPickerBuffer = None del self.colorPickerTex del self.colorPickerImage def __startEditor(self, editModel, editTexture, backgroundShader=MODEL_COLOR_SHADER): print "I: TexturePainter.__startEditor" # this is needed as on startup the editor may not have had a window etc. self.__windowEvent() if not editModel or not editTexture: print "W: TexturePainter.__startEditor: model or texture invalid", editModel, editTexture return False self.editModel = editModel self.editTexture = editTexture self.editImage = None self.backgroundShader = backgroundShader if type(self.editTexture) == Texture: # if the image to modify is a texture, create a pnmImage which we modify self.editImage = PNMImage() # copy the image from the texture to the working layer self.editTexture.store(self.editImage) else: self.editImage = self.editTexture # create the brush for painting self.painter = PNMPainter(self.editImage) self.setBrushSettings(*self.getBrushSettings()) self.__updateModel() # start edit messenger.send(EVENT_TEXTUREPAINTER_STARTEDIT) for startEvent in TEXTUREPAINTER_START_PAINT_EVENTS: self.accept(startEvent, self.__startPaint) for stopEvent in TEXTUREPAINTER_STOP_PAINT_EVENTS: self.accept(stopEvent, self.__stopPaint) self.modelColorCam.node().copyLens( WindowManager.activeWindow.camera.node().getLens()) taskMgr.add(self.__paintTask, 'paintTask') #modelModificator.toggleEditmode(False) self.isPainting = False def __stopEditor(self): print "I: TexturePainter.__stopEditor" for startEvent in TEXTUREPAINTER_START_PAINT_EVENTS: self.ignore(startEvent) for stopEvent in TEXTUREPAINTER_STOP_PAINT_EVENTS: self.ignore(stopEvent) taskMgr.remove('paintTask') # stop edit end # must be reset before we loose the properties if self.editModel and self.editTexture and self.editImage: try: # hide the model from cam 2 self.editModel.hide(BitMask32.bit(1)) self.editModel = None except: print "E: TexturePainter.__stopEditor: the model has already been deleted" # stop edit messenger.send(EVENT_TEXTUREPAINTER_STOPEDIT) self.editImage = None self.editTexture = None self.painter = None self.brush = None #modelModificator.toggleEditmode(True) def __updateModel(self): if self.editModel: # create a image with the same size of the texture textureSize = (self.editTexture.getXSize(), self.editTexture.getYSize()) # create a dummy node, where we setup the parameters for the background rendering loadPaintNode = NodePath(PandaNode('paintnode')) loadPaintNode.setShader(Shader.make(self.backgroundShader), 10001) loadPaintNode.setShaderInput('texsize', textureSize[0], textureSize[1], 0, 0) # copy the state onto the camera self.modelColorCam.node().setInitialState(loadPaintNode.getState()) # the camera gets a special bitmask, to show/hide models from it self.modelColorCam.node().setCameraMask(BitMask32.bit(1)) if False: # doesnt work, but would be nicer (not messing with the default render state) hiddenNode = NodePath(PandaNode('hiddennode')) hiddenNode.hide(BitMask32.bit(1)) showTroughNode = NodePath(PandaNode('showtroughnode')) showTroughNode.showThrough(BitMask32.bit(1)) self.modelColorCam.node().setTagStateKey( 'show-on-backrender-cam') self.modelColorCam.node().setTagState('False', hiddenNode.getState()) self.modelColorCam.node().setTagState( 'True', showTroughNode.getState()) render.setTag('show-on-backrender-cam', 'False') self.editModel.setTag('show-on-backrender-cam', 'True') else: # make only the model visible to the background camera render.hide(BitMask32.bit(1)) self.editModel.showThrough(BitMask32.bit(1)) # --- start the paint tasks --- def __startPaint(self): self.isPainting = True def __stopPaint(self): self.isPainting = False # --- modification tasks --- def __textureUpdateTask(self, task=None): ''' modify the texture using the edited image ''' if type(self.editTexture) == Texture: self.editTexture.load(self.editImage) if task: # task may be None return task.again def __paintTask(self, task): #print "I: TexturePainter.__paintTask:" if not WindowManager.activeWindow or not WindowManager.activeWindow.mouseWatcherNode.hasMouse( ): '''print " - abort:", WindowManager.activeWindow if WindowManager.activeWindow: print " - mouse:", WindowManager.activeWindow.mouseWatcherNode.hasMouse()''' return task.cont # update the camera according to the active camera #self.modelColorCam.setMat(render, WindowManager.activeWindow.camera.getMat(render)) mpos = base.mouseWatcherNode.getMouse() x_ratio = min(max(((mpos.getX() + 1) / 2), 0), 1) y_ratio = min(max(((mpos.getY() + 1) / 2), 0), 1) mx = int(x_ratio * self.windowSizeX) my = self.windowSizeY - int(y_ratio * self.windowSizeY) self.colorPickerScene.setShaderInput('mousepos', x_ratio, y_ratio, 0, 1) if self.colorPickerTex.hasRamImage(): self.colorPickerTex.store(self.colorPickerImage) # get the color below the mousepick from the rendered frame r = self.colorPickerImage.getRedVal(0, 0) g = self.colorPickerImage.getGreenVal(0, 0) b = self.colorPickerImage.getBlueVal(0, 0) # calculate uv-texture position from the color x = r + ((b % 16) * 256) y = g + ((b // 16) * 256) if self.isPainting: self.__paintPixel(x, y) self.__textureUpdateTask() else: # this might happen if no frame has been rendered yet since creation of the texture print "W: TexturePainter.__paintTask: colorPickerTex.hasRamMipmapImage() =", self.colorPickerTex.hasRamImage( ) return task.cont def __paintPixel(self, x, y): ''' paint at x/y with the defined settings ''' imageMaxX = self.editImage.getXSize() imageMaxY = self.editImage.getYSize() def inImage(x, y): ''' is the given x/y position within the image ''' return ((imageMaxX > x >= 0) and (imageMaxY > y >= 0)) # how smooth should be painted if self.paintSmooth: # a smooth brush hardness = 1.0 else: # a hard brush hardness = 0.1 hardness = min(1.0, max(0.05, hardness)) # the paint radius radius = int(round(self.paintSize / 2.0)) radiusSquare = float(radius * radius) # a function to get the brush color/strength, depending on the radius def getBrushColor(diffPosX, diffPosY): distance = diffPosX**2 + diffPosY**2 brushStrength = ( 1 - (min(distance, radiusSquare) / radiusSquare)) / hardness return min(1.0, max(0.0, brushStrength)) if inImage(x, y): if self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_POINT: if self.paintEffect in [ PNMBrush.BESet, PNMBrush.BEBlend, PNMBrush.BEDarken, PNMBrush.BELighten ]: # render a spot into the texture self.painter.drawPoint(x, y) elif self.paintEffect in [ TEXTUREPAINTER_BRUSH_FLATTEN, TEXTUREPAINTER_BRUSH_SMOOTH, TEXTUREPAINTER_BRUSH_RANDOMIZE ]: if self.paintEffect == TEXTUREPAINTER_BRUSH_SMOOTH: # calculate average values data = dict() smoothRadius = 2 for dx in xrange(-radius, radius + 1): for dy in xrange(-radius, radius + 1): if inImage(x + dx, y + dy): average = VBase4D(0) dividor = 0 for px in xrange(-smoothRadius, smoothRadius + 1): for py in xrange( -smoothRadius, smoothRadius + 1): if inImage(x + dx + px, y + dy + py): average += self.editImage.getXelA( x + dx + px, y + dy + py) dividor += 1 average /= float(dividor) data[(x + dx, y + dy)] = average # save to image for (px, py), newValue in data.items(): currentValue = self.editImage.getXelA(px, py) diffValue = currentValue - newValue dx = px - x dy = py - y multiplier = getBrushColor(dx, dy) print dx, dy, multiplier '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' '''r = currentValue.getX() * (1-multiplier*self.paintColor.getX()) + diffValue.getX() * multiplier*self.paintColor.getX() g = currentValue.getY() * (1-multiplier*self.paintColor.getY()) + diffValue.getY() * multiplier*self.paintColor.getY() b = currentValue.getZ() * (1-multiplier*self.paintColor.getZ()) + diffValue.getZ() * multiplier*self.paintColor.getZ() a = currentValue.getW() * (1-multiplier*self.paintColor.getW()) + diffValue.getW() * multiplier*self.paintColor.getW()''' r = currentValue.getX( ) - multiplier * diffValue.getX() g = currentValue.getY( ) - multiplier * diffValue.getY() b = currentValue.getZ( ) - multiplier * diffValue.getZ() a = currentValue.getW( ) - multiplier * diffValue.getW() if self.editImage.hasAlpha(): self.editImage.setXelA(px, py, VBase4D(r, g, b, a)) else: self.editImage.setXel(px, py, VBase3D(r, g, b)) #self.editImage.setXelA(x,y,value) if self.paintEffect == TEXTUREPAINTER_BRUSH_FLATTEN: dividor = 0 average = VBase4D(0) for dx in xrange(-radius, radius + 1): for dy in xrange(-radius, radius + 1): if inImage(x + dx, y + dy): multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' dividor += multiplier average += self.editImage.getXelA( x + dx, y + dy) * multiplier average /= dividor for dx in xrange(-radius, radius + 1): for dy in xrange(-radius, radius + 1): if inImage(x + dx, y + dy): multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' currentValue = self.editImage.getXelA( x + dx, y + dy) r = currentValue.getX() * ( 1 - multiplier * self.paintColor.getX() ) + average.getX( ) * multiplier * self.paintColor.getX() g = currentValue.getY() * ( 1 - multiplier * self.paintColor.getY() ) + average.getY( ) * multiplier * self.paintColor.getY() b = currentValue.getZ() * ( 1 - multiplier * self.paintColor.getZ() ) + average.getZ( ) * multiplier * self.paintColor.getZ() a = currentValue.getW() * ( 1 - multiplier * self.paintColor.getW() ) + average.getW( ) * multiplier * self.paintColor.getW() if self.editImage.hasAlpha(): self.editImage.setXelA( x + dx, y + dy, VBase4D(r, g, b, a)) else: self.editImage.setXel( x + dx, y + dy, VBase3D(r, g, b)) elif self.paintEffect == TEXTUREPAINTER_BRUSH_RANDOMIZE: for dx in xrange(-radius, radius + 1): for dy in xrange(-radius, radius + 1): if inImage(x + dx, y + dy): r = VBase4D( random.random() * self.paintColor.getX() - self.paintColor.getX() / 2., random.random() * self.paintColor.getY() - self.paintColor.getY() / 2., random.random() * self.paintColor.getZ() - self.paintColor.getZ() / 2., random.random() * self.paintColor.getW() - self.paintColor.getW() / 2.) multiplier = getBrushColor(dx, dy) '''if self.paintSmooth: multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy))) / (radius*radius) else: # not sure if this is correct multiplier = ((radius-math.fabs(dx))*(radius-math.fabs(dy)))''' currentValue = self.editImage.getXelA( x + dx, y + dy) self.editImage.setXelA( x + dx, y + dy, currentValue + r * multiplier) elif self.paintMode == TEXTUREPAINTER_FUNCTION_READ: if inImage(x, y): col = self.editImage.getXelA(x, y) if self.editImage.hasAlpha(): self.paintColor = VBase4D(col[0], col[1], col[2], col[3]) else: self.paintColor = VBase4D(col[0], col[1], col[2], 1.0) messenger.send(EVENT_TEXTUREPAINTER_BRUSHCHANGED) elif self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_LINE: if self.lastPoint != None: self.painter.drawLine(x, y, self.lastPoint[0], self.lastPoint[1]) elif self.paintMode == TEXTUREPAINTER_FUNCTION_PAINT_RECTANGLE: if self.lastPoint != None: self.painter.drawRectangle(x, y, self.lastPoint[0], self.lastPoint[1]) self.lastPoint = (x, y)