import pygame
from OpenGL.GL import *
from util import QuadTreeR
import math
class Surface:
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
self.dx = p2[0] - p1[0]
self.dy = p2[1] - p1[1]
try:
self.m_x = float(self.dy) / float(self.dx)
except ZeroDivisionError:
self.m_x = 1e999
self.b_x = p1[1] - self.m_x * p1[0]
try:
self.m_y = float(self.dx) / float(self.dy)
except ZeroDivisionError:
self.m_y = 1e999
self.b_y = p1[0] - self.m_y * p1[1]
self.bbox = pygame.Rect(p1,(self.dx,self.dy))
self.bbox.normalize()
def lineSideTest(self, point):
if self.m_x > -1.0 and self.m_x < 1.0:
if self.dx > 0:
if point[1] < self.m_x * point[0] + self.b_x:
return True
else:
if point[1] > self.m_x * point[0] + self.b_x:
return True
else:
if self.dy > 0:
if point[0] > self.m_y * point[1] + self.b_y:
return True
else:
if point[0] < self.m_y * point[1] + self.b_y:
return True
return False
def collidePoint(self, point):
if self.bbox.collidepoint(point[0],point[1]):
return self.lineSideTest(point)
def collideRect(self, rect):
if not self.bbox.colliderect(rect):
return False
return self.lineSideTest(rect.bottomleft) or \
self.lineSideTest(rect.bottomright) or \
self.lineSideTest(rect.topright) or \
self.lineSideTest(rect.topright)
def draw(self):
angle = math.atan(self.m_x)
if self.dx < 0 or self.dy < 0:
arrow = (angle+3*math.pi/2) % (2*math.pi)
else:
arrow = (angle+math.pi/2) % (2*math.pi)
anglepoint = (math.cos(arrow) * 10, math.sin(arrow) * 10)
glPushMatrix()
glDisable(GL_TEXTURE_2D)
if self.dx > 0:
py = self.bbox.top else:
py = self.bbox.bottom - 1
if self.dy > 0:
px = self.bbox.right - 1
else:
px = self.bbox.left
glColor4f(1.0,0.0,0.0,0.25)
glBegin(GL_TRIANGLES)
glVertex3f(self.p2[0], self.p2[1], 0)
glVertex3f(self.p1[0], self.p1[1], 0)
glVertex3f(px, py, 0)
glEnd()
glColor3f(1.0,1.0,1.0)
glBegin(GL_LINES)
glVertex3f(self.p1[0],self.p1[1],0)
glVertex3f(self.p2[0],self.p2[1],0)
glVertex3f(self.bbox.centerx, self.bbox.centery, 0)
glVertex3f(self.bbox.centerx + anglepoint[0], self.bbox.centery + anglepoint[1], 0)
glEnd()
glPopMatrix()
class Solid:
def __init__(self, p1, p2):
self.rect = pygame.Rect(p1,(p2[0]-p1[0],p2[1]-p1[1]))
self.rect.normalize()
self.bbox = self.rect
def collidePoint(self, point):
return self.rect.collidepoint(point[0],point[1])
def collideRect(self, rect):
return bool(self.rect.colliderect(rect))
def draw(self):
glPushMatrix()
glDisable(GL_TEXTURE_2D)
glColor4f(1.0,0.0,0.0,0.25)
glBegin(GL_QUADS)
glVertex(self.rect.left, self.rect.bottom, 0)
glVertex(self.rect.left, self.rect.top, 0)
glVertex(self.rect.right, self.rect.top, 0)
glVertex(self.rect.right, self.rect.bottom, 0)
glEnd()
glColor3f(1.0,1.0,1.0)
glBegin(GL_LINE_LOOP)
glVertex(self.rect.left, self.rect.bottom, 0)
glVertex(self.rect.left, self.rect.top, 0)
glVertex(self.rect.right, self.rect.top, 0)
glVertex(self.rect.right, self.rect.bottom, 0)
glEnd()
glPopMatrix()
class SurfaceSet:
surfaces = None
def __init__(self, f):
if isinstance(f, str) or isinstance(f, unicode):
fo = open(f, 'r')
self.parse(fo)
fo.close()
else:
self.parse(f)
def parse(self, f):
surfaces = []
mf = (1,1)
for line in f:
args = line.split()
if not args:
continue
cmd = args[0]
args = args[1:]
if cmd == 'tilesize':
mf = (int(args[0]),int(args[1]))
elif cmd == 'surface':
p1 = (int(args[0])*mf[0],int(args[1])*mf[1])
p2 = (int(args[2])*mf[0],int(args[3])*mf[1])
surfaces.append(Surface(p1,p2))
elif cmd == 'solid':
p1 = (int(args[0])*mf[0],int(args[1])*mf[1])
p2 = (int(args[2])*mf[0],int(args[3])*mf[1])
surfaces.append(Solid(p1,p2))
f.close()
bbox = surfaces[0].bbox.unionall([s.bbox for s in surfaces[1:]])
self.surfaces = QuadTreeR(bbox)
for s in surfaces:
self.surfaces.add(s.bbox, s)
def collidePoint(self,point):
colliders = self.surfaces.collidePointWalk(point)
for s in colliders:
if s.collidePoint(point):
return True
return False
def collideRect(self, rect):
for s in self.surfaces.collideRectWalk(rect):
if s.collideRect(rect):
return True
return False
def draw(self):
for s in self.surfaces:
s.draw()
self.surfaces.draw()
def add(self, s):
return self.surfaces.add(s.bbox, s)
def remove(self, s):
return self.surfaces.remove(s)