Created
March 18, 2011 07:29
-
-
Save z0w0/875732 to your computer and use it in GitHub Desktop.
A python program with a wx interface for directly rendering and editing Blockland brick files (.blb). @blockland.us
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#--------> | |
# BLB Editor | |
# by Zack "Zack0Wack0" Corr | |
# Updated: 04/02/11 | |
#-------- | |
import sys,os,wx | |
from time import strftime | |
import wx.stc | |
from wx import glcanvas | |
from OpenGL.GL import * | |
from OpenGL.GLU import gluBuild2DMipmaps | |
from PIL import Image | |
name = "BLB Editor" | |
version = 0.25 | |
title = name + " v" + str(version) | |
description = "BLB Editor is an application for editing Blockland brick files (.blb). \nIt includes a 3D canvas for rendering your current brick model,\n a styled text editor and a range of other features." | |
author = "Zack0Wack0" | |
website = "http://www.zack0wack0.com" | |
#--------> | |
# Cross OS Compatibility | |
#-------- | |
if wx.Platform == '__WXMSW__': | |
runningOS = "WINDOWS" | |
faces = { 'times': 'Times New Roman', | |
'mono' : 'Courier New', | |
'helv' : 'Arial', | |
'other': 'Comic Sans MS', | |
'size' : 10, | |
'size2': 8, | |
} | |
elif wx.Platform == '__WXMAC__': | |
runningOS = "MAC" | |
faces = { 'times': 'Times New Roman', | |
'mono' : 'Monaco', | |
'helv' : 'Arial', | |
'other': 'Comic Sans MS', | |
'size' : 12, | |
'size2': 10, | |
} | |
else: | |
runningOS = "OTHER" #it's probably linux or something | |
faces = { 'times': 'Times', | |
'mono' : 'Courier', | |
'helv' : 'Helvetica', | |
'other': 'new century schoolbook', | |
'size' : 12, | |
'size2': 10, | |
} | |
#--------> | |
# BLB Handling | |
#-------- | |
class Handler: | |
"""Handles all the BLB parsing and writing.""" #lol I never got around to it | |
def __init__(self): | |
pass | |
#--------> | |
# GUI | |
#-------- | |
id_file_new = 0 | |
id_file_open = 1 | |
id_file_import = 2 | |
id_file_save = 3 | |
id_file_saveas = 4 | |
id_file_exit = 10 | |
id_view_zoomin = 5 | |
id_view_zoomout = 6 | |
id_view_refresh = 7 | |
id_view_axii = 8 | |
id_view_grid = 9 | |
id_help_about = 11 | |
class Application(wx.App): | |
"""Controls everything.""" | |
def __init__(self,title,version): | |
self.saved = False | |
self.text = "" | |
self.file = "" | |
self.directory = "" | |
self.title = title | |
self.handler = Handler() | |
wipe = open("log.txt","w") | |
wipe.write(strftime("%d/%m/%Y %H:%M:%S") + "\n") | |
wipe.close() | |
wx.App.__init__(self,redirect=True,filename="log.txt") | |
def OnInit(self): | |
print self.title + " by Zack \"Zack0Wack0\" Corr" | |
self.frame = wx.Frame(None,-1,self.title,pos=(50,50),size=(640,480),style=wx.DEFAULT_FRAME_STYLE) | |
try: | |
self.icon = wx.Icon("icon.ico",wx.BITMAP_TYPE_ICO) | |
self.frame.SetIcon(self.icon) | |
except: | |
pass | |
self.frame.app = self | |
self.statusbar = self.frame.CreateStatusBar() | |
self.menubar = wx.MenuBar() | |
self.fileMenu = wx.Menu() | |
self.fileMenuNew = self.fileMenu.Append(id_file_new,"&New\tCtrl+N") | |
self.Bind(wx.EVT_MENU,self.onNew,id=id_file_new) | |
self.fileMenuOpen = self.fileMenu.Append(id_file_open,"&Open...\tCtrl+O") | |
self.Bind(wx.EVT_MENU,self.onOpen,id=id_file_open) | |
self.fileMenuImport = self.fileMenu.Append(id_file_import,"&Import...\tCtrl+I") | |
self.Bind(wx.EVT_MENU,self.onImport,id=id_file_import) | |
self.fileMenuSave = self.fileMenu.Append(id_file_save,"&Save\tCtrl+S") | |
self.Bind(wx.EVT_MENU,self.onQuickSave,id=id_file_save) | |
self.fileMenuSaveAs = self.fileMenu.Append(id_file_saveas,"Save &As...") | |
self.Bind(wx.EVT_MENU,self.onSave,id=id_file_saveas) | |
self.fileMenu.AppendSeparator() | |
self.fileMenuExit = self.fileMenu.Append(id_file_exit,"Exit") | |
self.Bind(wx.EVT_MENU,self.onExit,id=id_file_exit) | |
self.viewMenu = wx.Menu() | |
self.viewMenuZoomIn = self.viewMenu.Append(id_view_zoomin,"Zoom &In\tCtrl+=") | |
self.Bind(wx.EVT_MENU,self.onZoomIn,id=id_view_zoomin) | |
self.viewMenuZoomOut = self.viewMenu.Append(id_view_zoomout,"Zoom &Out\tCtrl+-") | |
self.Bind(wx.EVT_MENU,self.onZoomOut,id=id_view_zoomout) | |
self.viewMenuRefresh = self.viewMenu.Append(id_view_refresh,"&Refresh\tCtrl+R") | |
self.Bind(wx.EVT_MENU,self.onRefresh,id=id_view_refresh) | |
self.viewMenuAxii = self.viewMenu.Append(id_view_axii,"&Toggle Axii\tCtrl+M") | |
self.Bind(wx.EVT_MENU,self.onToggleAxii,id=id_view_axii) | |
self.viewMenuGrid = self.viewMenu.Append(id_view_grid,"&Toggle Grid\tCtrl+G") | |
self.Bind(wx.EVT_MENU,self.onToggleGrid,id=id_view_grid) | |
self.helpMenu = wx.Menu() | |
self.helpMenuAbout = self.helpMenu.Append(id_help_about,"&About") | |
self.Bind(wx.EVT_MENU,self.onAbout,id=id_help_about) | |
self.menubar.Append(self.fileMenu,"File") | |
self.menubar.Append(self.viewMenu,"View") | |
self.menubar.Append(self.helpMenu,"Help") | |
self.frame.SetMenuBar(self.menubar) | |
self.frame.Bind(wx.EVT_CLOSE,self.onExit) | |
self.frame.Show(True) | |
self.frame.SetSize((640, 480)) | |
self.frame.Centre() | |
self.panel = MainPanel(self.frame,app=self) | |
self.SetTopWindow(self.frame) | |
self.newFile(True) | |
print "Successfully started up." | |
return True | |
def openFile(self): | |
doOpen = True | |
if self.file != "" and self.saved != True: | |
doOpen = False | |
dialog = wx.MessageDialog(self.frame,"You haven't saved your current file. Do you want to save it before opening a new file?","Opening a file",wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION) | |
result = dialog.ShowModal() | |
dialog.Destroy() | |
if result == wx.ID_YES: | |
self.saveFile() | |
doOpen = True | |
elif result == wx.ID_NO: | |
doOpen = True | |
if not doOpen: | |
return | |
dialog = wx.FileDialog(self.frame,"Open",self.directory,self.file,"Blockland Brick Files (*.blb)|*.blb",wx.OPEN) | |
if dialog.ShowModal() == wx.ID_OK: | |
self.file = dialog.GetFilename() | |
self.directory = dialog.GetDirectory() | |
try: | |
reader = open(os.path.join(self.directory,self.file),"r") | |
text = "" | |
for line in reader: | |
text = text + line | |
self.panel.text.SetText(text) | |
reader.close() | |
self.frame.SetStatusText("Opened " + self.file + " at " + strftime("%H:%M:%S") + ".") | |
self.saved = True | |
self.frame.SetTitle(self.title + " - " + self.file) | |
self.refresh(True) | |
except: | |
self.frame.SetStatusText("Failed to open.") | |
dialog.Destroy() | |
def importFile(self): | |
pass | |
def newFile(self,forced=False): | |
doNewFile = True | |
if not self.saved and not forced: | |
doNewFile = False | |
dialog = wx.MessageDialog(self.frame,"You haven't saved your current file. Do you want to save it now?","New file",wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION) | |
result = dialog.ShowModal() | |
dialog.Destroy() | |
if result == wx.ID_YES: | |
self.saveFile() | |
doNewFile = True | |
elif result == wx.ID_NO: | |
doNewFile = True | |
if doNewFile: | |
self.file = "" | |
self.directory = "" | |
self.text = "" | |
self.saved = True | |
self.panel.text.SetText("") | |
self.frame.SetTitle(self.title) | |
def saveFileAs(self): | |
dialog = wx.FileDialog(self.frame,"Save As",self.directory,self.file,"Blockland Brick Files (*.blb)|*.blb",wx.SAVE | wx.OVERWRITE_PROMPT) | |
if dialog.ShowModal() == wx.ID_OK: | |
self.file = dialog.GetFilename() | |
self.directory = dialog.GetDirectory() | |
dialog.Destroy() | |
self.saveFile() | |
return | |
dialog.Destroy() | |
def saveFile(self): | |
if self.saved: | |
return | |
if self.file != "": | |
try: | |
writer = open(os.path.join(self.directory,self.file),"w") | |
writer.write(self.panel.text.GetText()) | |
writer.close() | |
self.frame.SetStatusText("Saved " + self.file + " at " + strftime("%H:%M:%S") + ".") | |
self.saved = True | |
self.frame.SetTitle(self.title + " - " + self.file) | |
except: | |
self.frame.SetStatusText("Failed to save.") | |
else: | |
self.saveFileAs() | |
def exit(self): | |
self.frame.Destroy() | |
def about(self): | |
info = wx.AboutDialogInfo() | |
try: | |
info.SetIcon(self.icon) | |
except: | |
pass | |
info.SetName(name) | |
info.SetVersion(str(version)) | |
info.SetDescription(description) | |
info.SetWebSite(website) | |
info.AddDeveloper(author) | |
wx.AboutBox(info) | |
def refresh(self,reset=False): | |
lines = self.panel.text.GetText() | |
if lines == "": | |
return | |
lines = lines.split("\n") | |
try: | |
size = lines[0] | |
size = size.strip().split() | |
modelSize = [int(size[0]),int(size[1]),int(size[2])] | |
type = lines[1] | |
if type == "BRICK": | |
#doesn't support normal bricks "yet" | |
return | |
lines = lines[2:] | |
except: | |
return | |
linecount = -1 | |
polygons = [] | |
for line in lines: | |
linecount = linecount + 1 | |
if len(line) >= 4: | |
if line[0:4] == "TEX:" and len(lines)-linecount >= 15: | |
successes = 0 | |
texture = line[4:] | |
colour = [] | |
if lines[linecount+1][0:9].strip() == "POSITION:": | |
pos1 = lines[linecount+2].strip().split() | |
pos2 = lines[linecount+3].strip().split() | |
pos3 = lines[linecount+4].strip().split() | |
pos4 = lines[linecount+5].strip().split() | |
try: | |
pos1X = float(pos1[0]) | |
pos1Y = float(pos1[1]) | |
pos1Z = float(pos1[2]) | |
pos1 = [pos1X,pos1Y,pos1Z] | |
pos2X = float(pos2[0]) | |
pos2Y = float(pos2[1]) | |
pos2Z = float(pos2[2]) | |
pos2 = [pos2X,pos2Y,pos2Z] | |
pos3X = float(pos3[0]) | |
pos3Y = float(pos3[1]) | |
pos3Z = float(pos3[2]) | |
pos3 = [pos3X,pos3Y,pos3Z] | |
pos4X = float(pos4[0]) | |
pos4Y = float(pos4[1]) | |
pos4Z = float(pos4[2]) | |
pos4 = [pos4X,pos4Y,pos4Z] | |
successes = successes + 1 | |
except: | |
continue | |
if lines[linecount+6][0:10].strip() == "UV COORDS:": | |
uv1 = lines[linecount+7].strip().split() | |
uv2 = lines[linecount+8].strip().split() | |
uv3 = lines[linecount+9].strip().split() | |
uv4 = lines[linecount+10].strip().split() | |
try: | |
uv1X = float(uv1[0]) | |
uv1Y = float(uv1[1]) | |
uv1 = [uv1X,uv1Y] | |
uv2X = float(uv2[0]) | |
uv2Y = float(uv2[1]) | |
uv2 = [uv2X,uv2Y] | |
uv3X = float(uv3[0]) | |
uv3Y = float(uv3[1]) | |
uv3 = [uv3X,uv3Y] | |
uv4X = float(uv4[0]) | |
uv4Y = float(uv4[1]) | |
uv4 = [uv4X,uv4Y] | |
successes = successes + 1 | |
except: | |
continue | |
if lines[linecount+11][0:7].strip() == "COLORS:" and len(lines)-linecount >= 20: | |
colour1 = lines[linecount+12].strip().split() | |
colour2 = lines[linecount+13].strip().split() | |
colour3 = lines[linecount+14].strip().split() | |
colour4 = lines[linecount+15].strip().split() | |
try: | |
colour1R = float(colour1[0]) | |
colour1G = float(colour1[1]) | |
colour1B = float(colour1[2]) | |
colour1A = float(colour1[3]) | |
colour1 = [colour1R,colour1G,colour1B,colour1A] | |
colour2R = float(colour2[0]) | |
colour2G = float(colour2[1]) | |
colour2B = float(colour2[2]) | |
colour2A = float(colour2[3]) | |
colour2 = [colour2R,colour2G,colour2B,colour2A] | |
colour3R = float(colour3[0]) | |
colour3G = float(colour3[1]) | |
colour3B = float(colour3[2]) | |
colour3A = float(colour3[3]) | |
colour3 = [colour3R,colour3G,colour3B,colour3A] | |
colour4R = float(colour4[0]) | |
colour4G = float(colour4[1]) | |
colour4B = float(colour4[2]) | |
colour4A = float(colour4[3]) | |
colour4 = [colour4R,colour4G,colour4B,colour4A] | |
colour = [colour1,colour2,colour3,colour4] | |
successes = successes + 1 | |
except: | |
continue | |
if lines[linecount+16][0:8].strip() == "NORMALS:": | |
normal1 = lines[linecount+17].strip().split() | |
normal2 = lines[linecount+18].strip().split() | |
normal3 = lines[linecount+19].strip().split() | |
normal4 = lines[linecount+20].strip().split() | |
try: | |
normal1X = float(normal1[0]) | |
normal1Y = float(normal1[1]) | |
normal1Z = float(normal1[2]) | |
normal1 = [normal1X,normal1Y,normal1Z] | |
normal2X = float(normal2[0]) | |
normal2Y = float(normal2[1]) | |
normal2Z = float(normal2[2]) | |
normal2 = [normal2X,normal2Y,normal2Z] | |
normal3X = float(normal3[0]) | |
normal3Y = float(normal3[1]) | |
normal3Z = float(normal3[2]) | |
normal3 = [normal3X,normal3Y,normal3Z] | |
normal4X = float(normal4[0]) | |
normal4Y = float(normal4[1]) | |
normal4Z = float(normal4[2]) | |
normal4 = [normal4X,normal4Y,normal4Z] | |
successes = successes + 1 | |
except: | |
continue | |
if lines[linecount+11][0:8].strip() == "NORMALS:": | |
normal1 = lines[linecount+12].strip().split() | |
normal2 = lines[linecount+13].strip().split() | |
normal3 = lines[linecount+14].strip().split() | |
normal4 = lines[linecount+15].strip().split() | |
try: | |
normal1X = float(normal1[0]) | |
normal1Y = float(normal1[1]) | |
normal1Z = float(normal1[2]) | |
normal1 = [normal1X,normal1Y,normal1Z] | |
normal2X = float(normal2[0]) | |
normal2Y = float(normal2[1]) | |
normal2Z = float(normal2[2]) | |
normal2 = [normal2X,normal2Y,normal2Z] | |
normal3X = float(normal3[0]) | |
normal3Y = float(normal3[1]) | |
normal3Z = float(normal3[2]) | |
normal3 = [normal3X,normal3Y,normal3Z] | |
normal4X = float(normal4[0]) | |
normal4Y = float(normal4[1]) | |
normal4Z = float(normal4[2]) | |
normal4 = [normal4X,normal4Y,normal4Z] | |
successes = successes + 1 | |
except: | |
continue | |
if successes > 2: | |
poly = [texture,[pos1,pos2,pos3,pos4],[normal1,normal2,normal3,normal4],[uv1,uv2,uv3,uv4],colour] | |
polygons.append(poly) | |
self.panel.canvas.updateModel(polygons,modelSize,reset) | |
self.panel.canvas.Refresh(False) | |
if len(polygons) > 0: | |
self.frame.SetStatusText("Refreshed " + str(len(polygons)) + " polygons at " + strftime("%H:%M:%S") + ".") | |
def zoomIn(self): | |
self.panel.canvas.zoomIn() | |
self.panel.canvas.Refresh(False) | |
def zoomOut(self): | |
self.panel.canvas.zoomOut() | |
self.panel.canvas.Refresh(False) | |
def toggleGrid(self): | |
self.panel.canvas.toggleGrid() | |
self.panel.canvas.Refresh(False) | |
def toggleAxii(self): | |
self.panel.canvas.toggleAxii() | |
self.panel.canvas.Refresh(False) | |
def onNew(self,event): | |
self.newFile() | |
def onOpen(self,event): | |
self.openFile() | |
def onImport(self,event): | |
self.importFile() | |
def onSave(self,event): | |
self.saveFileAs() | |
def onQuickSave(self,event): | |
self.saveFile() | |
def onZoomIn(self,event): | |
self.zoomIn() | |
def onZoomOut(self,event): | |
self.zoomOut() | |
def onToggleGrid(self,event): | |
self.toggleGrid() | |
def onToggleAxii(self,event): | |
self.toggleAxii() | |
def onRefresh(self,event): | |
self.refresh() | |
def onAbout(self,event): | |
self.about() | |
def onExit(self,event): | |
if not self.saved: | |
close = False | |
dialog = wx.MessageDialog(self.frame,"You haven't saved your current file. Do you want to save it now?","Exiting program",wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION) | |
result = dialog.ShowModal() | |
dialog.Destroy() | |
if result == wx.ID_YES: | |
self.saveFile() | |
close = True | |
elif result == wx.ID_NO: | |
close = True | |
if close: | |
self.exit() | |
else: | |
self.exit() | |
class MainPanel(wx.Panel): | |
"""The main GUI.""" | |
def __init__(self,parent,app=None): | |
wx.Panel.__init__(self,parent,-1) | |
self.parent = parent | |
self.box = wx.BoxSizer(wx.HORIZONTAL) | |
self.canvas = CanvasPanel(self) | |
self.canvas.SetSize((400,400)) | |
self.box.Add(self.canvas,6,wx.EXPAND) | |
self.text = TextPanel(self) | |
self.box.Add(self.text,4,wx.EXPAND) | |
self.text.EmptyUndoBuffer() | |
self.text.Colourise(0,-1) | |
self.text.SetMarginType(1,wx.stc.STC_MARGIN_NUMBER) | |
self.text.SetMarginWidth(1,25) | |
self.SetAutoLayout(True) | |
self.SetSizer(self.box) | |
class TextPanel(wx.stc.StyledTextCtrl): | |
def __init__(self,parent,id=-1,pos=wx.DefaultPosition,size=wx.DefaultSize,style=0): | |
self.keywords = "TEX POSITION UV COORDS NORMALS COVERAGE SPECIAL BRICK" | |
wx.stc.StyledTextCtrl.__init__(self,parent,id,pos,size,style) | |
self.parent = parent | |
self.SetKeyWords(0,self.keywords) | |
self.SetProperty("fold","1") | |
self.SetProperty("tab.timmy.whinge.level","1") | |
self.SetMargins(0,0) | |
self.SetViewWhiteSpace(False) | |
self.SetMarginWidth(2,8) | |
self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,"face:%(helv)s,size:%(size)d" % faces) | |
self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,"back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) | |
self.StyleSetSpec(wx.stc.STC_STYLE_CONTROLCHAR,"face:%(other)s" % faces) | |
self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,"fore:#FFFFFF,back:#0000FF,bold") | |
self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,"fore:#000000,back:#FF0000,bold") | |
self.StyleSetSpec(1,"fore:#00AAFF,face:%(helv)s,size:%(size)d" % faces) | |
self.SetLexer(wx.stc.STC_LEX_CONTAINER) | |
self.Bind(wx.EVT_KEY_DOWN,self.onKeyPressed) | |
self.Bind(wx.stc.EVT_STC_STYLENEEDED,self.onStyleNeeded) | |
def onKeyPressed(self,event): | |
event.Skip() | |
newText = self.GetText() | |
if self.parent.parent.app.text != newText: | |
if self.parent.parent.app.saved: | |
if self.parent.parent.app.file != "": | |
self.parent.parent.SetTitle(self.parent.parent.app.title + " - *" + self.parent.parent.app.file) | |
self.parent.parent.app.saved = False | |
self.parent.parent.app.text = newText | |
def onStyleNeeded(self,event): | |
end = event.GetPosition() | |
start = self.GetEndStyled() | |
self.StartStyling(start,0x1f) | |
for i in range(start,end + 1): | |
c = self.GetCharAt(i) | |
if 48 <= c <= 57: | |
self.SetStyling(1,1) | |
else: | |
self.SetStyling(1,0) | |
class CanvasPanel(glcanvas.GLCanvas): | |
"""The 3D canvas.""" | |
def __init__(self,parent): | |
glcanvas.GLCanvas.__init__(self,parent,-1) | |
self.polygons = [] | |
self.parent = parent | |
self.init = False | |
self.lastx = self.x = 0 | |
self.lasty = self.y = 0 | |
self.size = None | |
self.scale = 0.1 | |
self.noRotateFix = False | |
self.axii = True | |
self.grid = False | |
self.gridList = None | |
self.maxScale = 0.1 | |
self.minScale = 0.05 | |
self.Bind(wx.EVT_ERASE_BACKGROUND,self.onEraseBackground) | |
self.Bind(wx.EVT_SIZE,self.onSize) | |
self.Bind(wx.EVT_PAINT,self.onPaint) | |
self.Bind(wx.EVT_LEFT_DOWN,self.onMouseDown) | |
self.Bind(wx.EVT_LEFT_UP,self.onMouseUp) | |
self.Bind(wx.EVT_MOTION,self.onMouseMotion) | |
self.Bind(wx.EVT_KEY_DOWN,self.onKeyPressed) | |
def updateModel(self,polygons,modelSize,reset=False): | |
self.polygons = polygons | |
self.modelSize = modelSize | |
volume = self.modelSize[0] * self.modelSize[1] | |
self.maxScale = (pow(volume,2.1) / pow(volume,2.5)) * 0.75 | |
self.minScale = 0.01 | |
if reset: | |
glScale(self.maxScale,self.maxScale,self.maxScale) | |
self.scale = self.maxScale | |
def loadImage(self,imageFile,sWrap=GL_REPEAT,tWrap=GL_REPEAT,rWrap=GL_REPEAT): | |
im = Image.open(imageFile) | |
width = im.size[0] | |
height = im.size[1] | |
image = im.tostring("raw","RGBX",0,-1) | |
id = glGenTextures(1) | |
glPixelStorei(GL_UNPACK_ALIGNMENT,1) | |
glBindTexture(GL_TEXTURE_2D,id) | |
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,image) | |
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,sWrap) | |
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,tWrap) | |
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_R,rWrap) | |
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) | |
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) | |
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE) | |
return id | |
def zoomIn(self): | |
glScale(1.03,1.03,1.03) | |
self.noRotateFix = True | |
def zoomOut(self): | |
glScale(0.97,0.97,0.97) | |
self.noRotateFix = True | |
def toggleAxii(self): | |
if self.axii: | |
self.axii = False | |
else: | |
self.axii = True | |
def toggleGrid(self): | |
if self.grid: | |
self.grid = False | |
else: | |
self.grid = True | |
def onEraseBackground(self,event): | |
pass | |
def onSize(self,event): | |
size = self.size = self.GetClientSize() | |
if self.GetContext(): | |
self.SetCurrent() | |
glViewport(0,0,size.width,size.height) | |
event.Skip() | |
def onPaint(self,event): | |
dc = wx.PaintDC(self) | |
self.SetCurrent() | |
if not self.init: | |
self.initCanvas() | |
self.init = True | |
self.onDraw() | |
def onMouseDown(self,event): | |
self.CaptureMouse() | |
self.x, self.y = self.lastx, self.lasty = event.GetPosition() | |
def onMouseUp(self,event): | |
if self and self.HasCapture(): | |
self.ReleaseMouse() | |
def onMouseMotion(self,event): | |
if event.Dragging() and event.LeftIsDown(): | |
self.lastx, self.lasty = self.x, self.y | |
self.x, self.y = event.GetPosition() | |
self.Refresh(False) | |
if event.MiddleIsDown(): | |
wheelRot = event.GetWheelRotation() | |
if wheelrot != 0: | |
if wheelrot > 0: | |
self.zoomIn() | |
else: | |
self.zoomOut() | |
self.Refresh(False) | |
def onKeyPressed(self,event): | |
if event.GetKeyCode() == wx.WXK_UP: | |
if self.zoom >= 6: | |
return | |
self.zoom = self.zoom + 1 | |
if event.GetKeyCode() == wx.WXK_DOWN: | |
if self.zoom <= 0: | |
return | |
self.zoom = self.zoom - 1 | |
event.Skip() | |
def initCanvas(self): | |
try: | |
self.texture = { | |
"TOP": self.loadImage("brickTOP.bmp"), | |
"SIDE": self.loadImage("brickSIDE.bmp"), | |
"RAMP": self.loadImage("brickRAMP.bmp"), | |
"BOTTOMEDGE": self.loadImage("brickBOTTOMEDGE.bmp",GL_CLAMP,GL_CLAMP), | |
"BOTTOMLOOP": self.loadImage("brickBOTTOMLOOP.bmp"), | |
"PRINT": self.loadImage("brickPRINT.bmp") | |
} | |
self.usesTextures = True | |
print "Textures loaded successfully." | |
except Exception as exception: | |
self.usesTextures = False | |
print "Textures failed to load. (" + str(exception) + ")" | |
glEnable(GL_LIGHTING) | |
glEnable(GL_LIGHT0) | |
glMatrixMode(GL_PROJECTION) | |
glFrustum(-0.5,0.5,-0.5,0.5,1,3) | |
glMatrixMode(GL_MODELVIEW) | |
glTranslatef(0,0,-2) | |
glRotatef(self.y,1.0,0.0,0.0) | |
glRotatef(self.x,0.0,1.0,0.0) | |
glEnable(GL_DEPTH_TEST) | |
def onDraw(self): | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) | |
glDisable(GL_LIGHTING) | |
useColour = False | |
glEnable(GL_COLOR_MATERIAL) | |
faceID = -1 | |
for poly in self.polygons: | |
faceID += 1 | |
texture = poly[0] | |
pos1 = poly[1][0] | |
pos2 = poly[1][1] | |
pos3 = poly[1][2] | |
pos4 = poly[1][3] | |
normal1 = poly[2][0] | |
normal2 = poly[2][1] | |
normal3 = poly[2][2] | |
normal4 = poly[2][3] | |
uv1 = poly[3][0] | |
uv2 = poly[3][1] | |
uv3 = poly[3][2] | |
uv4 = poly[3][3] | |
colour = poly[4] | |
useColour = False | |
if len(colour) > 0: | |
colour1 = colour[0] | |
colour2 = colour[1] | |
colour3 = colour[2] | |
colour4 = colour[3] | |
#due to openGL lamos you can't enable and disable blend during drawing, so sucks for you if you need each vertex a different transparency | |
if colour1[3] < 1.0: | |
glEnable(GL_BLEND) | |
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA) | |
useColour = True | |
else: | |
glColor4f(1,1,1,1) | |
glEnable(GL_TEXTURE_2D) | |
if self.usesTextures and not useColour: | |
glBindTexture(GL_TEXTURE_2D,self.texture[texture]) | |
glBegin(GL_QUADS) | |
if useColour: | |
glColor4f(colour1[0],colour1[1],colour1[2],colour1[3]) | |
else: | |
glTexCoord2f(uv1[0],uv1[1]) | |
glNormal3f(normal1[0],normal1[1],normal1[2]) | |
glVertex3f(pos1[0],pos1[1],(pos1[2]) / 3) | |
if useColour: | |
glColor4f(colour2[0],colour2[1],colour2[2],colour2[3]) | |
else: | |
glTexCoord2f(uv2[0],uv2[1]) | |
glNormal3f(normal2[0],normal2[1],normal2[2]) | |
glVertex3f(pos2[0],pos2[1],(pos2[2]) / 3) | |
if useColour: | |
glColor4f(colour3[0],colour3[1],colour3[2],colour3[3]) | |
else: | |
glTexCoord2f(uv3[0],uv3[1]) | |
glNormal3f(normal3[0],normal3[1],normal3[2]) | |
glVertex3f(pos3[0],pos3[1],(pos3[2]) / 3) | |
if useColour: | |
glColor4f(colour4[0],colour4[1],colour4[2],colour4[3]) | |
else: | |
glTexCoord2f(uv4[0],uv4[1]) | |
glNormal3f(normal4[0],normal4[1],normal4[2]) | |
glVertex3f(pos4[0],pos4[1],(pos4[2]) / 3) | |
glEnd() | |
glFlush() | |
if not useColour: | |
glDisable(GL_TEXTURE_2D) | |
else: | |
glDisable(GL_BLEND) | |
glDisable(GL_COLOR_MATERIAL) | |
if self.axii: | |
glLineWidth(2) | |
glDisable(GL_LIGHTING) | |
glBegin(GL_LINES) | |
glColor4f(1,0,0,1) | |
glVertex3f(0,0,0) | |
glVertex3f(10000,0,0) | |
glColor4f(0,1,0,1) | |
glVertex3f(0,0,0) | |
glVertex3f(0,10000,0) | |
glColor4f(0,0,1,1) | |
glVertex3f(0,0,0) | |
glVertex3f(0,0,10000) | |
glEnd() | |
glEnable(GL_LIGHTING) | |
if self.grid: | |
if self.gridList == None: | |
self.parent.parent.SetStatusText("Compiling the grid. This could take a while.") | |
self.gridList = glGenLists(1) | |
glNewList(self.gridList,GL_COMPILE) | |
glLineWidth(1) | |
glBegin(GL_LINES) | |
for x in range(64): | |
for y in range(64): | |
x = float(x) | |
y = float(y) | |
glColor4f(0.5,0.5,0.5,1) | |
a = (x - 32) - 0.5 | |
b = (y - 32) - 0.5 | |
c = x - 0.5 | |
d = y - 0.5 | |
glVertex3f(a,b,0) | |
glVertex3f(a,d,0) | |
glVertex3f(a,b,0) | |
glVertex3f(c,b,0) | |
glEnd() | |
glEndList() | |
glDisable(GL_LIGHTING) | |
glCallList(self.gridList) | |
glEnable(GL_LIGHTING) | |
self.parent.parent.SetStatusText("Finished compiling the grid.") | |
else: | |
glDisable(GL_LIGHTING) | |
glCallList(self.gridList) | |
glEnable(GL_LIGHTING) | |
if self.size is None: | |
self.size = self.GetClientSize() | |
w, h = self.size | |
w = max(w,1.0) | |
h = max(h,1.0) | |
xScale = 180.0 / w | |
yScale = 180.0 / h | |
if not self.noRotateFix: | |
glRotate((self.y - self.lasty) * yScale,1,0,0) | |
glRotate((self.x - self.lastx) * xScale,0,1,0) | |
else: | |
self.noRotateFix = False | |
self.SwapBuffers() | |
#--------> | |
# Run | |
#-------- | |
BLBEditor = Application(title,version) | |
BLBEditor.MainLoop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment