Cellular automata in GLSL+PyQT. Various rulesets can be found by checking out individual commits. http://hut.pm/cellmade_gallery.html
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

176 lines
6.2 KiB

from cellmade.lib.fpscounter import FPSCounter
from cellmade.lib.openstruct import OpenStruct
from cellmade.lib.glhelper import *
from cellmade.glwidget import GLWidget
from cellmade.simulation import Simulation
from cellmade.uihelper import *
from PyQt5 import QtOpenGL
from PyQt5 import QtCore
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from OpenGL.GLU import gluPerspective
import time
class Controller(object):
def __init__(self, win):
self.win = win
self.fps = 0
self.tick = 0
self.conf = self._readConfig()
self.fpsCounter = FPSCounter(lambda fps:setattr(self, 'fps', fps))
self.sim = Simulation(self)
self._assignMenuActions()
self._initGL()
self.params = OpenStruct(
p1=0, p2=0,
frameskip=self.conf.general.frameskip,
hsvshift=0,
hsvactive=False,
b1=False, b2=False,
diffH=False, diffV=False,
)
self._updateFrameskip()
def _assignMenuActions(self):
self.win.actionQuit.triggered.connect(qApp.quit)
movestep = 0.1
def handlePause(): self.sim.pause ^= True
def handleStep(): self.sim.doStep = True
def handleReset(): self.sim.doReset = True
def handleUp(): self.sim.cameraMove(0, movestep)
def handleDown(): self.sim.cameraMove(0, -movestep)
def handleLeft(): self.sim.cameraMove(-movestep, 0)
def handleRight(): self.sim.cameraMove(movestep, 0)
def handleCenter(): self.sim.cameraReset()
def handleFullscreen():
if self.win.stacker.currentIndex() == 0:
self.win.stacker.setCurrentIndex(1)
self.win.layoutStandalone.addWidget(self.win.gl)
self.win.gl.viewStandalone()
else:
self.win.stacker.setCurrentIndex(0)
self.win.horizontalLayout_4.addWidget(self.win.gl)
self.win.gl.viewInterfaced()
def handleZoomIn(): self.sim.cameraZoom(0.9)
def handleZoomOut(): self.sim.cameraZoom(1.11)
def handleFrameSkipPlus():
self.params.frameskip += 1
self._updateFrameskip()
def handleFrameSkipMinus():
self.params.frameskip -= 1
self._updateFrameskip()
def handleFrameSkipReset():
self.params.frameskip = 1
self._updateFrameskip()
for var, fn in locals().items():
if var.startswith("handle"):
action = getattr(self.win, 'action' + var[6:])
action.triggered.connect(fn)
@self.win.zoomSlider.valueChanged.connect
def handleZoomSlider(value):
self.sim.zoomLevel = sliderValue2ZoomLevel(value)
self.win.textRenderShader.setText(open(
"cellmade/shader/render.frag", "r").read())
self.win.textStepShader.setText(open(
"cellmade/shader/step.frag", "r").read())
@self.win.buttonRecompile.clicked.connect
def handleRecompile():
try:
self.sim.recompileShaders(
stepfrag=self.win.textStepShader.toPlainText(),
renderfrag=self.win.textRenderShader.toPlainText())
except RuntimeError as e:
print(e.args[0])
self.win.buttonPause.clicked.connect(handlePause)
def connectDialWithSpinner(name, dialToSpinFactor=0.01):
def get(widget):
return getattr(self.win, widget + '_' + name)
def handleDial(value):
self.params[name] = float(value) * dialToSpinFactor
get('spin').setValue(self.params[name])
def handleSpin(value):
self.params[name] = float(value)
get('dial').setValue(self.params[name] / dialToSpinFactor)
get('dial').valueChanged.connect(handleDial)
get('spin').valueChanged.connect(handleSpin)
for name in 'hsvshift', 'p1', 'p2':
connectDialWithSpinner(name)
connectDialWithSpinner('frameskip', 1)
#--------------------------------
# Connect all the Checkboxes
#--------------------------------
def connectCheckbox(name):
def handleCheckbox(value):
self.params[name] = value
getattr(self.win, 'check_' + name).clicked.connect(handleCheckbox)
for name in 'diffH', 'diffV', 'b1', 'b2', 'hsvactive':
connectCheckbox(name)
def _readConfig(self):
import configparser
configPath = "config.ini"
configParser = configparser.ConfigParser()
configParser.readfp(open(configPath, "r"))
def postProcess(value):
if value == "true": return True
if value == "false": return False
if value.isdigit(): return int(value)
return value
conf = OpenStruct()
for section in configParser.sections():
conf[section] = OpenStruct((k, postProcess(v)) \
for k, v in configParser.items(section))
return conf
def _initGL(self):
self.win.horizontalLayout_4.removeWidget(self.win.dummyWidget)
self.win.dummyWidget.hide()
self.win.gl = GLWidget(self)
self.win.horizontalLayout_4.addWidget(self.win.gl)
if self.conf.window.menu:
self.win.stacker.setCurrentIndex(0)
self.win.gl.viewInterfaced()
else:
self.win.stacker.setCurrentIndex(1)
self.win.gl.viewStandalone()
self.timer = QtCore.QTimer()
self.timer.setInterval(20)
self.timer.start()
self.timer.timeout.connect(self._glTimeout)
def _glTimeout(self):
self.tick += 1
self.fpsCounter.count()
self.win.gl.updateGL()
self.win.statusbar.showMessage("FPS: %f, Zoom: %f" % \
(self.fps, self.sim.zoomLevel))
self.win.label.setText(str(int(self.fps)))
def updateZoomSlider(self):
self.win.zoomSlider.setValue(zoomLevel2SliderValue(self.sim.zoomLevel))
def _updateFrameskip(self):
self.win.dial_frameskip.setValue(self.params.frameskip)
self.win.spin_frameskip.setValue(self.params.frameskip)