├── .DS_Store ├── .gitignore ├── Chapter01 ├── HelloWindow.py ├── PlotPixel.py ├── README.md └── StarSign.py ├── Chapter02 ├── CustomText.py ├── Polygons.py ├── PygameLine.py ├── README.md ├── RGBSpace.py └── ShowRaster.py ├── Chapter03 ├── BresenhamCircle.py ├── LinePlot.py ├── PlotLineNaive.py └── README.md ├── Chapter04 ├── Cube.py ├── HelloMesh.py ├── Mesh3D.py ├── OpenGLStarter.py └── README.md ├── Chapter05 ├── Cube.py ├── HelloLights.py ├── Mesh3D.py └── README.md ├── Chapter06 ├── Cube.py ├── HelloObject.py ├── Mesh3D.py ├── Object.py ├── README.md └── Transform.py ├── Chapter07 ├── AddingButton.py ├── Button.py ├── Cube.py ├── Mesh3D.py ├── MouseDrawing.py ├── Object.py ├── README.md ├── Settings.py ├── Transform.py └── Utils.py ├── Chapter08 ├── Button.py ├── Cube.py ├── DisplayTeapot.py ├── LoadMesh.py ├── Mesh3D.py ├── Object.py ├── Settings.py ├── Transform.py ├── Utils.py └── resources │ └── teapot.obj ├── Chapter09 ├── AddingButton.py ├── Button.py ├── Cube.py ├── DisplayTeapot.py ├── Grid.py ├── LoadMesh.py ├── Mesh3D.py ├── Object.py ├── Settings.py ├── Transform.py ├── Utils.py └── Vectors.py ├── Chapter10 ├── AddingButton.py ├── Animate.py ├── Button.py ├── Cube.py ├── DisplayTeapot.py ├── Display_Normals.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── Object.py ├── Settings.py ├── Transform.py └── Utils.py ├── Chapter11 ├── Animate.py ├── Button.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── Settings.py ├── Transform.py ├── Utils.py ├── models │ ├── cube.obj │ ├── plane.obj │ ├── plane2.obj │ └── planesm.obj └── startercode │ └── ExploreNormals.py ├── Chapter12 ├── Animate.py ├── Button.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── ScalingObjects.py ├── Settings.py ├── Transform.py └── Utils.py ├── Chapter13 ├── Animate.py ├── Button.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── ScalingObjects.py ├── Settings.py ├── Transform.py ├── TransformationMatrices.py └── Utils.py ├── Chapter14 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── ScalingObjects.py ├── Settings.py ├── Transform.py ├── TransformationMatrices.py └── Utils.py ├── Chapter15 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── FlyCamera.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── ScalingObjects.py ├── Settings.py ├── Transform.py ├── TransformationMatrices.py ├── Utils.py └── models │ └── teapotSM.obj ├── Chapter16 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── FlyCamera.py ├── Grid.py ├── LoadMesh.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── Quaternion.py ├── QuaternionTeapot.py ├── ScalingObjects.py ├── Settings.py ├── Transform.py ├── TransformationMatrices.py └── Utils.py ├── Chapter17 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── FlyCamera.py ├── GraphicsData.py ├── Grid.py ├── LoadMesh.py ├── Material.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── Quaternion.py ├── QuaternionTeapot.py ├── ScalingObjects.py ├── Settings.py ├── ShaderTeapot.py ├── Transform.py ├── TransformationMatrices.py ├── Uniform.py ├── Utils.py ├── shaders │ ├── vertexcolfrag.vs │ └── vertexcolvert.vs └── starter │ ├── AddingButton.py │ ├── Animate.py │ ├── Button.py │ ├── Camera.py │ ├── Camera2D.py │ ├── Cube.py │ ├── DisplayTeapot.py │ ├── Display_Normals.py │ ├── FlyCamera.py │ ├── GraphicsData.py │ ├── Grid.py │ ├── LoadMesh.py │ ├── Material.py │ ├── MathOGL.py │ ├── Mesh3D.py │ ├── NormalLights.py │ ├── Object.py │ ├── Quaternion.py │ ├── QuaternionTeapot.py │ ├── ScalingObjects.py │ ├── Settings.py │ ├── ShaderTeapot.py │ ├── Transform.py │ ├── TransformationMatrices.py │ ├── Uniform.py │ └── Utils.py ├── Chapter18 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── ExploreNormals.py ├── FlyCamera.py ├── Granny │ ├── granny.obj │ └── granny.png ├── GraphicsData.py ├── Grid.py ├── LoadMesh.py ├── Material.py ├── MathOGL.py ├── Mesh3D.py ├── NormalLights.py ├── Object.py ├── Quaternion.py ├── QuaternionTeapot.py ├── ScalingObjects.py ├── Settings.py ├── ShaderTeapot.py ├── Texture.py ├── Transform.py ├── TransformationMatrices.py ├── Uniform.py └── Utils.py ├── Chapter19 ├── Animate.py ├── Button.py ├── Camera.py ├── Camera2D.py ├── Cube.py ├── DisplayNormals.py ├── GraphicsData.py ├── Grid.py ├── Light.py ├── LoadMesh.py ├── Material.py ├── MathOGL.py ├── Mesh3D.py ├── Object.py ├── PBR.py ├── Quaternion.py ├── Settings.py ├── Sphere │ └── sphere.obj ├── Texture.py ├── Transform.py ├── Uniform.py ├── Utils.py └── shaders │ ├── pbrfrag.vs │ └── pbrvert.vs ├── LICENSE └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mathematics-for-Game-Programming-and-Computer-Graphics/5f7f3d3786decc6d8f877862da9ccf2062bdb4d1/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Chapter01/HelloWindow.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | done = False 11 | while not done: 12 | for event in pygame.event.get(): 13 | if event.type == pygame.QUIT: 14 | done = True 15 | 16 | pygame.display.update() 17 | pygame.quit() -------------------------------------------------------------------------------- /Chapter01/PlotPixel.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | done = False 11 | white = pygame.Color(255, 255, 255) 12 | 13 | 14 | def ToPyGameCoordinates(display, x, y): 15 | return x, display.get_height() - y 16 | 17 | while not done: 18 | for event in pygame.event.get(): 19 | if event.type == pygame.QUIT: 20 | done = True 21 | position = ToPyGameCoordinates(screen, 100, 100) 22 | pygame.draw.rect(screen, white, (position[0], position[1], 10, 10)) 23 | pygame.display.update() 24 | pygame.quit() -------------------------------------------------------------------------------- /Chapter01/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter01/StarSign.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | done = False 11 | white = pygame.Color(255, 255, 255) 12 | 13 | 14 | def DrawStar(x, y, size): 15 | pygame.draw.rect(screen, white, (x, y, size, size)) 16 | 17 | while not done: 18 | for event in pygame.event.get(): 19 | if event.type == pygame.QUIT: 20 | done = True 21 | DrawStar(121, 320, 15) 22 | DrawStar(327, 324, 15) 23 | DrawStar(691, 431, 20) 24 | DrawStar(697, 317, 10) 25 | DrawStar(626, 246, 30) 26 | DrawStar(343, 212, 10) 27 | DrawStar(653, 165, 10) 28 | DrawStar(773, 102, 10) 29 | DrawStar(822, 153, 10) 30 | pygame.display.update() 31 | pygame.quit() -------------------------------------------------------------------------------- /Chapter02/CustomText.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | screen_width = 800 5 | screen_height = 200 6 | screen = pygame.display.set_mode((screen_width, 7 | screen_height)) 8 | 9 | done = False 10 | white = pygame.Color(255, 255, 255) 11 | red = pygame.Color(255, 0, 0) 12 | 13 | pygame.font.init() 14 | font = pygame.font.Font('../fonts/Doctor Glitch.otf', 80) 15 | font2 = pygame.font.Font('../fonts/Bad Coma.ttf', 80) 16 | text = font.render('Penny de Byl', False, white) 17 | text2 = font.render('Adrian Devlin', False, red) 18 | while not done: 19 | for event in pygame.event.get(): 20 | if event.type == pygame.QUIT: 21 | done = True 22 | x = (screen_width - text.get_width()) / 2 23 | y = (screen_height - text.get_height()) / 2 24 | screen.blit(text, (x, y)) 25 | screen.blit(text2, (10, 10)) 26 | pygame.display.update() 27 | pygame.quit() 28 | -------------------------------------------------------------------------------- /Chapter02/Polygons.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | done = False 11 | 12 | white = pygame.Color(255, 255, 255) 13 | 14 | while not done: 15 | for event in pygame.event.get(): 16 | if event.type == pygame.QUIT: 17 | done = True 18 | pygame.draw.polygon(screen, white, ((250, 200), (600, 400), (400, 600))) 19 | pygame.display.update() 20 | pygame.quit() -------------------------------------------------------------------------------- /Chapter02/PygameLine.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | 4 | pygame.init() 5 | 6 | screen_width = 1000 7 | screen_heigth = 800 8 | 9 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 10 | 11 | done = False 12 | white = pygame.Color(255, 255, 255) 13 | green = pygame.Color(0, 255, 0) 14 | timesClicked = 0 15 | while not done: 16 | for event in pygame.event.get(): 17 | if event.type == pygame.QUIT: 18 | done = True 19 | elif event.type == MOUSEBUTTONDOWN: 20 | if timesClicked == 0: 21 | point1 = pygame.mouse.get_pos() 22 | else: 23 | point2 = pygame.mouse.get_pos() 24 | timesClicked += 1 25 | if timesClicked > 1: 26 | pygame.draw.line(screen, white, point1, point2, 1) 27 | timesClicked = 0 28 | 29 | pygame.display.update() 30 | pygame.quit() -------------------------------------------------------------------------------- /Chapter02/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter02/RGBSpace.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | done = False 11 | while not done: 12 | for event in pygame.event.get(): 13 | if event.type == pygame.QUIT: 14 | done = True 15 | 16 | for y in range(800): 17 | for x in range(1000): 18 | screen.set_at((x, y), pygame.Color(0, int(x / screen_width * 255), 19 | int(y / screen_heigth * 255))) 20 | 21 | pygame.display.update() 22 | pygame.quit() -------------------------------------------------------------------------------- /Chapter02/ShowRaster.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 960 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | #Add a title to the display window 11 | pygame.display.set_caption("A Beautiful Sunset") 12 | 13 | done = False 14 | 15 | # Load a background image 16 | background = pygame.image.load("../images/sunset.jpg") 17 | sprite = pygame.image.load("../images/bee-icon.png") 18 | 19 | while not done: 20 | for event in pygame.event.get(): 21 | if event.type == pygame.QUIT: 22 | done = True 23 | screen.blit(background, (0, 0)) 24 | screen.blit(sprite, (100, 100)) 25 | pygame.display.update() 26 | pygame.quit() -------------------------------------------------------------------------------- /Chapter03/BresenhamCircle.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * #support for getting mouse button events 3 | 4 | pygame.init() 5 | screen_width = 400 6 | screen_height = 400 7 | screen = pygame.display.set_mode((screen_width, 8 | screen_height)) 9 | done = False 10 | white = pygame.Color(255, 255, 255) 11 | 12 | def circle_points(x, y, center): 13 | screen.set_at((x + center[0], y + center[1]), white) 14 | screen.set_at((y + center[0], x + center[1]), white) 15 | screen.set_at((y + center[0], -x + center[1]), white) 16 | screen.set_at((x + center[0], -y + center[1]), white) 17 | screen.set_at((-x + center[0], -y + center[1]), white) 18 | screen.set_at((-y + center[0], -x + center[1]), white) 19 | screen.set_at((-y + center[0], x + center[1]), white) 20 | screen.set_at((-x + center[0], y + center[1]), white) 21 | 22 | 23 | def plot_circle(radius, center): 24 | x = 0 25 | y = radius 26 | d = 5/4.0 - radius 27 | circle_points(x, y, center) 28 | while y > x: 29 | if d < 0: # select E 30 | d = d + 2 * x + 3 31 | x += 1 32 | else: # select SE 33 | d = d + 2 * (x - y) + 5 34 | x = x + 1 35 | y = y - 1 36 | circle_points(x, y, center) 37 | 38 | while not done: 39 | for event in pygame.event.get(): 40 | if event.type == pygame.QUIT: 41 | done = True 42 | plot_circle(50, (200, 200)) 43 | pygame.display.update() 44 | pygame.quit() 45 | -------------------------------------------------------------------------------- /Chapter03/LinePlot.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen_width = 1000 6 | screen_heigth = 800 7 | 8 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 9 | 10 | white = pygame.Color(255, 255, 255) 11 | green = pygame.Color(0, 255, 0) 12 | xoriginoffset = int(screen.get_width() / 2) 13 | yoriginoffset = int(screen.get_height() / 2) 14 | 15 | done = False 16 | while not done: 17 | for event in pygame.event.get(): 18 | if event.type == pygame.QUIT: 19 | done = True 20 | 21 | # x axis 22 | for x in range(-500, 500): 23 | screen.set_at((x + xoriginoffset, yoriginoffset), green) 24 | 25 | # y axis 26 | for y in range(-400, 400): 27 | screen.set_at((xoriginoffset, y + yoriginoffset), green) 28 | 29 | # Line 30 | for x in range(-500, 500): 31 | y = int(10 * x) - 100 # LINE EQUATION 32 | screen.set_at((x + xoriginoffset, y + yoriginoffset), white) 33 | 34 | pygame.display.update() 35 | pygame.quit() -------------------------------------------------------------------------------- /Chapter03/PlotLineNaive.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | 4 | pygame.init() 5 | 6 | screen_width = 1000 7 | screen_heigth = 800 8 | 9 | screen = pygame.display.set_mode((screen_width, screen_heigth)) 10 | 11 | done = False 12 | 13 | white = pygame.Color(255, 255, 255) 14 | green = pygame.Color(0, 255, 0) 15 | timesClicked = 0 16 | 17 | def plot_line(point1, point2): 18 | x0, y0 = point1 19 | x1, y1 = point2 20 | dx = abs(x1 - x0) 21 | if x0 < x1: 22 | sx = 1 23 | else: 24 | sx = -1 25 | dy = -abs(y1 - y0) 26 | if y0 < y1: 27 | sy = 1 28 | else: 29 | sy = -1 30 | 31 | err = dx + dy 32 | 33 | while True: 34 | screen.set_at((x0, y0), white) 35 | if x0 == x1 and y0 == y1: 36 | break 37 | e2 = 2 * err 38 | if e2 >= dy: 39 | err += dy 40 | x0 += sx 41 | if e2 <= dx: 42 | err += dx 43 | y0 += sy 44 | 45 | 46 | while not done: 47 | for event in pygame.event.get(): 48 | if event.type == pygame.QUIT: 49 | done = True 50 | elif event.type == MOUSEBUTTONDOWN: 51 | if timesClicked == 0: 52 | point1 = pygame.mouse.get_pos() 53 | else: 54 | point2 = pygame.mouse.get_pos() 55 | timesClicked += 1 56 | if timesClicked > 1: 57 | plot_line(point1, point2) 58 | timesClicked = 0 59 | 60 | pygame.display.update() 61 | pygame.quit() -------------------------------------------------------------------------------- /Chapter03/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter04/Cube.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from Mesh3D import * 3 | 4 | class Cube(Mesh3D): 5 | def __init__(self): 6 | 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5), 13 | (0.5, -0.5, -0.5), 14 | (-0.5, -0.5, -0.5), 15 | (0.5, 0.5, 0.5), 16 | (-0.5, 0.5, 0.5), 17 | (0.5, 0.5, -0.5), 18 | (-0.5, 0.5, -0.5), 19 | (0.5, -0.5, -0.5), 20 | (0.5, -0.5, 0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, -0.5, -0.5), 23 | (-0.5, -0.5, 0.5), 24 | (-0.5, 0.5, 0.5), 25 | (-0.5, 0.5, -0.5), 26 | (-0.5, -0.5, -0.5), 27 | (0.5, -0.5, -0.5), 28 | (0.5, 0.5, -0.5), 29 | (0.5, 0.5, 0.5), 30 | (0.5, -0.5, 0.5)] 31 | 32 | self.traingles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 33 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 34 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 35 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 36 | 37 | 38 | -------------------------------------------------------------------------------- /Chapter04/HelloMesh.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | from Mesh3D import * 4 | from Cube import * 5 | from pygame.locals import * 6 | from OpenGL.GL import * 7 | from OpenGL.GLU import * 8 | 9 | pygame.init() 10 | 11 | screen_width = 500 12 | screen_heigth = 500 13 | 14 | screen = pygame.display.set_mode((screen_width, screen_heigth), DOUBLEBUF | OPENGL) 15 | pygame.display.set_caption("OpenGL in Python") 16 | done = False 17 | white = pygame.Color(255, 255, 255) 18 | gluPerspective(30, (screen_width // screen_heigth), 0.1, 100.0) 19 | # glOrtho(-1, 1, 1, -1, 0.1, 100.0) 20 | glTranslatef(0.0, 0.0, -3.0) 21 | mesh = Cube() 22 | 23 | while not done: 24 | for event in pygame.event.get(): 25 | if event.type == pygame.QUIT: 26 | done = True 27 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 28 | glRotatef(5, 1, 0, 1) 29 | mesh.draw() 30 | pygame.display.flip() 31 | pygame.time.wait(100) 32 | pygame.quit() -------------------------------------------------------------------------------- /Chapter04/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.traingles = [0, 2, 3, 0, 3, 1] 14 | 15 | def draw(self): 16 | for t in range(0, len(self.traingles), 3): 17 | glBegin(GL_LINE_LOOP) 18 | glVertex3fv(self.vertices[self.traingles[t]]) 19 | glVertex3fv(self.vertices[self.traingles[t + 1]]) 20 | glVertex3fv(self.vertices[self.traingles[t + 2]]) 21 | glEnd() -------------------------------------------------------------------------------- /Chapter04/OpenGLStarter.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | 5 | pygame.init() 6 | 7 | screen_width = 500 8 | screen_heigth = 500 9 | 10 | screen = pygame.display.set_mode((screen_width, screen_heigth), DOUBLEBUF | OPENGL) 11 | pygame.display.set_caption("OpenGL in Python") 12 | done = False 13 | white = pygame.Color(255, 255, 255) 14 | 15 | while not done: 16 | for event in pygame.event.get(): 17 | if event.type == pygame.QUIT: 18 | done = True 19 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 20 | pygame.display.flip() 21 | pygame.quit() -------------------------------------------------------------------------------- /Chapter04/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter05/HelloLights.py: -------------------------------------------------------------------------------- 1 | from Cube import * 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | pygame.init() 7 | screen_width = 500 8 | screen_height = 500 9 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 10 | pygame.display.set_caption('Lights in OpenGL') 11 | done = False 12 | white = pygame.Color(255, 255, 255) 13 | glMatrixMode(GL_PROJECTION) 14 | gluPerspective(60, (screen_width / screen_height), 0.1, 100.0) 15 | glMatrixMode(GL_MODELVIEW) 16 | glTranslatef(0.0, 0.0, -3.0) 17 | glEnable(GL_DEPTH_TEST) 18 | glEnable(GL_LIGHTING) 19 | 20 | glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) 21 | glLightfv(GL_LIGHT0, GL_AMBIENT, (1, 0, 1, 1)) 22 | glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 0, 0, 1)) 23 | glLightfv(GL_LIGHT0, GL_SPECULAR, (0, 1, 0, 1)) 24 | glMaterial(GL_FRONT, GL_DIFFUSE, (0, 1, 0, 1)) 25 | 26 | glEnable(GL_LIGHT0) 27 | 28 | # Change path name to suit your directory structure 29 | mesh = Cube(GL_POLYGON, "../images/bricks.jpg") 30 | 31 | while not done: 32 | for event in pygame.event.get(): 33 | if event.type == pygame.QUIT: 34 | done = True 35 | 36 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 37 | glRotatef(5, 1, 0, 1) 38 | mesh.draw() 39 | pygame.display.flip() 40 | pygame.time.wait(50) 41 | pygame.quit() 42 | -------------------------------------------------------------------------------- /Chapter05/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5)] 13 | 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def draw(self): 20 | glEnable(GL_TEXTURE_2D) 21 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 22 | glBindTexture(GL_TEXTURE_2D, self.texID) 23 | for t in range(0, len(self.triangles), 3): 24 | glBegin(self.draw_type) 25 | glTexCoord2fv(self.uvs[self.triangles[t]]) 26 | glVertex3fv(self.vertices[self.triangles[t]]) 27 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 28 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 29 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 30 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 31 | glEnd() 32 | glDisable(GL_TEXTURE_2D) 33 | 34 | def init_texture(self): 35 | self.texID = glGenTextures(1) 36 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 37 | width = self.texture.get_width() 38 | height = self.texture.get_height() 39 | glBindTexture(GL_TEXTURE_2D, self.texID) 40 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 41 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter05/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter06/HelloObject.py: -------------------------------------------------------------------------------- 1 | from Object import * 2 | from Cube import * 3 | from pygame.locals import * 4 | from OpenGL.GL import * 5 | from OpenGL.GLU import * 6 | 7 | pygame.init() 8 | 9 | screen_width = 500 10 | screen_height = 500 11 | 12 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 13 | pygame.display.set_caption("OpenGL in Python") 14 | done = False 15 | white = pygame.Color(255, 255, 255) 16 | glMatrixMode(GL_PROJECTION) 17 | gluPerspective(60, (screen_width / screen_height), 0.1, 100.0) 18 | glMatrixMode(GL_MODELVIEW) 19 | # glOrtho(-1, 1, 1, -1, 0.1, 100.0) 20 | glTranslatef(0.0, 0.0, -3.0) 21 | glEnable(GL_DEPTH_TEST) 22 | objects = [] 23 | cube = Object("Cube") 24 | cube.add_component(Transform((0, 0, 0))) 25 | cube.add_component(Cube(GL_POLYGON, "../images/wall.tif")) 26 | objects.append(cube) 27 | glEnable(GL_LIGHTING) 28 | glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) 29 | 30 | glEnable(GL_LIGHT0) 31 | glMaterialfv(GL_FRONT, GL_DIFFUSE, (0, 1, 0, 1)) 32 | clock = pygame.time.Clock() 33 | fps = 60 34 | while not done: 35 | for event in pygame.event.get(): 36 | if event.type == pygame.QUIT: 37 | done = True 38 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 39 | glRotatef(5, 1, 0, 1) 40 | for o in objects: 41 | o.update() 42 | pygame.display.flip() 43 | clock.tick(fps) 44 | pygame.quit() -------------------------------------------------------------------------------- /Chapter06/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | 32 | def int_texture(self): 33 | self.texID = glGenTextures(1) 34 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 35 | width = self.texture.get_width() 36 | height = self.texture.get_height() 37 | glBindTexture(GL_TEXTURE_2D, self.texID) 38 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 39 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter06/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | 4 | 5 | class Object: 6 | def __init__(self, obj_name): 7 | self.name = obj_name 8 | self.components = [] 9 | 10 | def add_component(self, component): 11 | if isinstance(component, Transform): 12 | self.components.insert(0, self.components) 13 | self.components.append(component) 14 | 15 | def update(self): 16 | glPushMatrix() 17 | for c in self.components: 18 | if isinstance(c, Transform): 19 | pos = c.get_position() 20 | glTranslatef(pos.x, pos.y, pos.z) 21 | if isinstance(c, Mesh3D): 22 | c.draw() 23 | glPopMatrix() 24 | -------------------------------------------------------------------------------- /Chapter06/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter06/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | class Transform: 4 | def __init__(self, position): 5 | self.set_position(position) 6 | 7 | def get_position(self): 8 | return self.position 9 | 10 | def set_position(self, position): 11 | self.position = pygame.math.Vector3(position) 12 | -------------------------------------------------------------------------------- /Chapter07/Button.py: -------------------------------------------------------------------------------- 1 | import pygame.mouse 2 | from OpenGL.GL import * 3 | from Utils import * 4 | from pygame.locals import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, o_color, p_color, on_click): 9 | self.screen = screen 10 | self.position = position 11 | self.width = width 12 | self.height = height 13 | self.normal_color = color 14 | self.over_color = o_color 15 | self.pressed_color = p_color 16 | self.on_click = on_click 17 | self.mouse_down = False 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], 24 | mouse_pos[0]) 25 | my = map_value(window_dimensions[2], window_dimensions[3], 26 | gui_dimensions[2], gui_dimensions[3], 27 | mouse_pos[1]) 28 | 29 | glPushMatrix() 30 | glLoadIdentity() 31 | # If the mouse is over the button 32 | if self.position[0] < mx < (self.position[0] + self.width) and self.position[1] < my < (self.position[1] + self.height): 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]) 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]) 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() -------------------------------------------------------------------------------- /Chapter07/Cube.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class Cube(Mesh3D): 4 | def __init__(self, draw_type, filename): 5 | self.vertices = [(0.5, -0.5, 0.5), 6 | (-0.5, -0.5, 0.5), 7 | (0.5, 0.5, 0.5), 8 | (-0.5, 0.5, 0.5), 9 | (0.5, 0.5, -0.5), 10 | (-0.5, 0.5, -0.5), 11 | (0.5, -0.5, -0.5), 12 | (-0.5, -0.5, -0.5), 13 | (0.5, 0.5, 0.5), 14 | (-0.5, 0.5, 0.5), 15 | (0.5, 0.5, -0.5), 16 | (-0.5, 0.5, -0.5), 17 | (0.5, -0.5, -0.5), 18 | (0.5, -0.5, 0.5), 19 | (-0.5, -0.5, 0.5), 20 | (-0.5, -0.5, -0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, 0.5, 0.5), 23 | (-0.5, 0.5, -0.5), 24 | (-0.5, -0.5, -0.5), 25 | (0.5, -0.5, -0.5), 26 | (0.5, 0.5, -0.5), 27 | (0.5, 0.5, 0.5), 28 | (0.5, -0.5, 0.5)] 29 | 30 | self.triangles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 31 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 32 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 33 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 34 | 35 | self.uvs = [(0.0, 0.0), 36 | (1.0, 0.0), 37 | (0.0, 1.0), 38 | (1.0, 1.0), 39 | (0.0, 1.0), 40 | (1.0, 1.0), 41 | (0.0, 1.0), 42 | (1.0, 1.0), 43 | (0.0, 0.0), 44 | (1.0, 0.0), 45 | (0.0, 0.0), 46 | (1.0, 0.0), 47 | (0.0, 0.0), 48 | (0.0, 1.0), 49 | (1.0, 1.0), 50 | (1.0, 0.0), 51 | (0.0, 0.0), 52 | (0.0, 1.0), 53 | (1.0, 1.0), 54 | (1.0, 0.0), 55 | (0.0, 0.0), 56 | (0.0, 1.0), 57 | (1.0, 1.0), 58 | (1.0, 0.0)] 59 | 60 | Mesh3D.draw_type = draw_type 61 | Mesh3D.texture = pygame.image.load(filename) 62 | Mesh3D.int_texture(self) -------------------------------------------------------------------------------- /Chapter07/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | glDisable(GL_TEXTURE_2D) 32 | 33 | def int_texture(self): 34 | self.texID = glGenTextures(1) 35 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 36 | width = self.texture.get_width() 37 | height = self.texture.get_height() 38 | glBindTexture(GL_TEXTURE_2D, self.texID) 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 40 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter07/MouseDrawing.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | 4 | pygame.init() 5 | screen_width = 800 6 | screen_height = 800 7 | screen = pygame.display.set_mode((screen_width, screen_height)) 8 | done = False 9 | white = pygame.Color(255, 255, 255) 10 | mouse_down = False 11 | last_mouse_pos =(0, 0) 12 | green = pygame.Color(0, 255, 0) 13 | button = (0, 0, 100, 30) 14 | while not done: 15 | pygame.draw.rect(screen, green, button) 16 | for event in pygame.event.get(): 17 | if event.type == pygame.QUIT: 18 | done = True 19 | elif event.type == MOUSEBUTTONDOWN and event.button == 1: 20 | mouse_down = True 21 | last_mouse_pos = pygame.mouse.get_pos() 22 | elif event.type == MOUSEBUTTONUP and event.button == 1: 23 | mouse_down = False 24 | elif event.type == MOUSEMOTION and mouse_down is True: 25 | pygame.draw.line(screen, white, last_mouse_pos, pygame.mouse.get_pos(), 5) 26 | last_mouse_pos = pygame.mouse.get_pos() 27 | elif event.type == MOUSEMOTION: 28 | mpos = pygame.mouse.get_pos() 29 | if button[0] < mpos[0] < (button[0] + button[2]) and button[1] < mpos[1] < (button[1] + button[3]): 30 | print("Mouse Over") 31 | pygame.display.update() 32 | pygame.quit() 33 | -------------------------------------------------------------------------------- /Chapter07/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | 5 | class Object: 6 | def __init__(self, obj_name): 7 | self.name = obj_name 8 | self.components = [] 9 | 10 | def add_component(self, component): 11 | if isinstance(component, Transform): 12 | self.components.insert(0, self.components) 13 | self.components.append(component) 14 | 15 | def update(self, events = None): 16 | glPushMatrix() 17 | for c in self.components: 18 | if isinstance(c, Transform): 19 | pos = c.get_position() 20 | glTranslatef(pos.x, pos.y, pos.z) 21 | if isinstance(c, Mesh3D): 22 | c.draw() 23 | if isinstance(c, Button): 24 | c.draw(events) 25 | 26 | glPopMatrix() 27 | 28 | def get_component(self, class_type): 29 | for c in self.components: 30 | if type(c) is class_type: 31 | return c 32 | return None 33 | -------------------------------------------------------------------------------- /Chapter07/README.md: -------------------------------------------------------------------------------- 1 | # Mathematics-for-Game-Programming-and-Computer-Graphics 2 | Mathematics for Game Programming and Computer Graphics, published by Packt 3 | -------------------------------------------------------------------------------- /Chapter07/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | -------------------------------------------------------------------------------- /Chapter07/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | class Transform: 4 | def __init__(self, position): 5 | self.set_position(position) 6 | 7 | def get_position(self): 8 | return self.position 9 | 10 | def set_position(self, position): 11 | self.position = pygame.math.Vector3(position) 12 | 13 | def move_x(self, amount): 14 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 15 | 16 | def move_y(self, amount): 17 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) -------------------------------------------------------------------------------- /Chapter07/Utils.py: -------------------------------------------------------------------------------- 1 | def map_value(current_min, current_max, new_min, new_max, value): 2 | current_range = current_max - current_min 3 | new_range = new_max - new_min 4 | return new_min + new_range * ((value - current_min) / current_range) -------------------------------------------------------------------------------- /Chapter08/Button.py: -------------------------------------------------------------------------------- 1 | # import math 2 | import pygame.mouse 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from pygame.locals import * 6 | from Settings import * 7 | 8 | class Button: 9 | def __init__(self, screen, position, width, height, color, o_color, p_color, on_click): 10 | self.screen = screen 11 | self.position = position 12 | self.width = width 13 | self.height = height 14 | self.normal_color = color 15 | self.over_color = o_color 16 | self.pressed_color = p_color 17 | self.on_click = on_click 18 | self.mouse_down = False 19 | 20 | 21 | def draw(self, events): 22 | mouse_pos = pygame.mouse.get_pos() 23 | mx = map_value(window_dimensions[0], window_dimensions[1], 24 | gui_dimensions[0], gui_dimensions[1], 25 | mouse_pos[0]) 26 | my = map_value(window_dimensions[2], window_dimensions[3], 27 | gui_dimensions[2], gui_dimensions[3], 28 | mouse_pos[1]) 29 | 30 | glPushMatrix() 31 | glLoadIdentity() 32 | # If the mouse is over the button 33 | if self.position[0] < mx < (self.position[0] + self.width) and self.position[1] < my < (self.position[1] + self.height): 34 | for e in events: 35 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 36 | self.mouse_down = True 37 | self.on_click() 38 | elif e.type == MOUSEBUTTONUP and e.button == 1: 39 | self.mouse_down = False 40 | if self.mouse_down: 41 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 42 | else: 43 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]) 44 | else: 45 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]) 46 | glBegin(GL_POLYGON) 47 | glVertex2f(self.position[0], self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1]) 49 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 50 | glVertex2f(self.position[0], self.position[1] + self.height) 51 | glEnd() 52 | glPopMatrix() -------------------------------------------------------------------------------- /Chapter08/Cube.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class Cube(Mesh3D): 4 | def __init__(self, draw_type, filename): 5 | self.vertices = [(0.5, -0.5, 0.5), 6 | (-0.5, -0.5, 0.5), 7 | (0.5, 0.5, 0.5), 8 | (-0.5, 0.5, 0.5), 9 | (0.5, 0.5, -0.5), 10 | (-0.5, 0.5, -0.5), 11 | (0.5, -0.5, -0.5), 12 | (-0.5, -0.5, -0.5), 13 | (0.5, 0.5, 0.5), 14 | (-0.5, 0.5, 0.5), 15 | (0.5, 0.5, -0.5), 16 | (-0.5, 0.5, -0.5), 17 | (0.5, -0.5, -0.5), 18 | (0.5, -0.5, 0.5), 19 | (-0.5, -0.5, 0.5), 20 | (-0.5, -0.5, -0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, 0.5, 0.5), 23 | (-0.5, 0.5, -0.5), 24 | (-0.5, -0.5, -0.5), 25 | (0.5, -0.5, -0.5), 26 | (0.5, 0.5, -0.5), 27 | (0.5, 0.5, 0.5), 28 | (0.5, -0.5, 0.5)] 29 | 30 | self.triangles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 31 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 32 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 33 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 34 | 35 | self.uvs = [(0.0, 0.0), 36 | (1.0, 0.0), 37 | (0.0, 1.0), 38 | (1.0, 1.0), 39 | (0.0, 1.0), 40 | (1.0, 1.0), 41 | (0.0, 1.0), 42 | (1.0, 1.0), 43 | (0.0, 0.0), 44 | (1.0, 0.0), 45 | (0.0, 0.0), 46 | (1.0, 0.0), 47 | (0.0, 0.0), 48 | (0.0, 1.0), 49 | (1.0, 1.0), 50 | (1.0, 0.0), 51 | (0.0, 0.0), 52 | (0.0, 1.0), 53 | (1.0, 1.0), 54 | (1.0, 0.0), 55 | (0.0, 0.0), 56 | (0.0, 1.0), 57 | (1.0, 1.0), 58 | (1.0, 0.0)] 59 | 60 | Mesh3D.draw_type = draw_type 61 | Mesh3D.texture = pygame.image.load(filename) 62 | Mesh3D.int_texture(self) -------------------------------------------------------------------------------- /Chapter08/LoadMesh.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class LoadMesh(Mesh3D): 4 | def __init__(self, draw_type, model_filename): 5 | self.vertices, self.triangles = self.load_drawing(model_filename) 6 | self.draw_type = draw_type 7 | 8 | def draw(self): 9 | for t in range(0, len(self.triangles), 3): 10 | glBegin(self.draw_type) 11 | glVertex3fv(self.vertices[self.triangles[t]]) 12 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 13 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 14 | glEnd() 15 | glDisable(GL_TEXTURE_2D) 16 | 17 | 18 | def load_drawing(self, filename): 19 | vertices = [] 20 | triangles = [] 21 | with open(filename) as fp: 22 | line = fp.readline() 23 | while line: 24 | if line[:2] == "v ": 25 | vx, vy, vz = [float(value) for value in 26 | line[2:].split()] 27 | vertices.append((vx, vy, vz)) 28 | if line[:2] == "f ": 29 | t1, t2, t3 = [value for value in 30 | line[2:].split()] 31 | triangles.append( 32 | [int(value) for value in t1.split('/')][0] - 1) 33 | triangles.append( 34 | [int(value) for value in t2.split('/')][0] - 1) 35 | triangles.append( 36 | [int(value) for value in t3.split('/')][0] - 1) 37 | line = fp.readline() 38 | return vertices, triangles 39 | 40 | -------------------------------------------------------------------------------- /Chapter08/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | glDisable(GL_TEXTURE_2D) 32 | 33 | def int_texture(self): 34 | self.texID = glGenTextures(1) 35 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 36 | width = self.texture.get_width() 37 | height = self.texture.get_height() 38 | glBindTexture(GL_TEXTURE_2D, self.texID) 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 40 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter08/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | 5 | class Object: 6 | def __init__(self, obj_name): 7 | self.name = obj_name 8 | self.components = [] 9 | 10 | def add_component(self, component): 11 | if isinstance(component, Transform): 12 | self.components.insert(0, self.components) 13 | self.components.append(component) 14 | 15 | def update(self, events = None): 16 | glPushMatrix() 17 | for c in self.components: 18 | if isinstance(c, Transform): 19 | pos = c.get_position() 20 | glTranslatef(pos.x, pos.y, pos.z) 21 | if isinstance(c, Mesh3D): 22 | c.draw() 23 | if isinstance(c, Button): 24 | c.draw(events) 25 | 26 | glPopMatrix() 27 | 28 | def get_component(self, class_type): 29 | for c in self.components: 30 | if type(c) is class_type: 31 | return c 32 | return None 33 | -------------------------------------------------------------------------------- /Chapter08/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | -------------------------------------------------------------------------------- /Chapter08/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | class Transform: 4 | def __init__(self, position): 5 | self.set_position(position) 6 | 7 | def get_position(self): 8 | return self.position 9 | 10 | def set_position(self, position): 11 | self.position = pygame.math.Vector3(position) 12 | 13 | def move_x(self, amount): 14 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 15 | 16 | def move_y(self, amount): 17 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) -------------------------------------------------------------------------------- /Chapter08/Utils.py: -------------------------------------------------------------------------------- 1 | def map_value(current_min, current_max, new_min, new_max, value): 2 | current_range = current_max - current_min 3 | new_range = new_max - new_min 4 | return new_min + new_range * ((value - current_min) / current_range) -------------------------------------------------------------------------------- /Chapter09/Button.py: -------------------------------------------------------------------------------- 1 | # import math 2 | import pygame.mouse 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from pygame.locals import * 6 | from Settings import * 7 | 8 | class Button: 9 | def __init__(self, screen, position, width, height, color, o_color, p_color, on_click): 10 | self.screen = screen 11 | self.position = position 12 | self.width = width 13 | self.height = height 14 | self.normal_color = color 15 | self.over_color = o_color 16 | self.pressed_color = p_color 17 | self.on_click = on_click 18 | self.mouse_down = False 19 | 20 | 21 | def draw(self, events): 22 | mouse_pos = pygame.mouse.get_pos() 23 | mx = map_value(window_dimensions[0], window_dimensions[1], 24 | gui_dimensions[0], gui_dimensions[1], 25 | mouse_pos[0]) 26 | my = map_value(window_dimensions[2], window_dimensions[3], 27 | gui_dimensions[2], gui_dimensions[3], 28 | mouse_pos[1]) 29 | 30 | glPushMatrix() 31 | glLoadIdentity() 32 | # If the mouse is over the button 33 | if self.position[0] < mx < (self.position[0] + self.width) and self.position[1] < my < (self.position[1] + self.height): 34 | for e in events: 35 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 36 | self.mouse_down = True 37 | self.on_click() 38 | elif e.type == MOUSEBUTTONUP and e.button == 1: 39 | self.mouse_down = False 40 | if self.mouse_down: 41 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 42 | else: 43 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]) 44 | else: 45 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]) 46 | glBegin(GL_POLYGON) 47 | glVertex2f(self.position[0], self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1]) 49 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 50 | glVertex2f(self.position[0], self.position[1] + self.height) 51 | glEnd() 52 | glPopMatrix() -------------------------------------------------------------------------------- /Chapter09/Cube.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class Cube(Mesh3D): 4 | def __init__(self, draw_type, filename): 5 | self.vertices = [(0.5, -0.5, 0.5), 6 | (-0.5, -0.5, 0.5), 7 | (0.5, 0.5, 0.5), 8 | (-0.5, 0.5, 0.5), 9 | (0.5, 0.5, -0.5), 10 | (-0.5, 0.5, -0.5), 11 | (0.5, -0.5, -0.5), 12 | (-0.5, -0.5, -0.5), 13 | (0.5, 0.5, 0.5), 14 | (-0.5, 0.5, 0.5), 15 | (0.5, 0.5, -0.5), 16 | (-0.5, 0.5, -0.5), 17 | (0.5, -0.5, -0.5), 18 | (0.5, -0.5, 0.5), 19 | (-0.5, -0.5, 0.5), 20 | (-0.5, -0.5, -0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, 0.5, 0.5), 23 | (-0.5, 0.5, -0.5), 24 | (-0.5, -0.5, -0.5), 25 | (0.5, -0.5, -0.5), 26 | (0.5, 0.5, -0.5), 27 | (0.5, 0.5, 0.5), 28 | (0.5, -0.5, 0.5)] 29 | 30 | self.triangles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 31 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 32 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 33 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 34 | 35 | self.uvs = [(0.0, 0.0), 36 | (1.0, 0.0), 37 | (0.0, 1.0), 38 | (1.0, 1.0), 39 | (0.0, 1.0), 40 | (1.0, 1.0), 41 | (0.0, 1.0), 42 | (1.0, 1.0), 43 | (0.0, 0.0), 44 | (1.0, 0.0), 45 | (0.0, 0.0), 46 | (1.0, 0.0), 47 | (0.0, 0.0), 48 | (0.0, 1.0), 49 | (1.0, 1.0), 50 | (1.0, 0.0), 51 | (0.0, 0.0), 52 | (0.0, 1.0), 53 | (1.0, 1.0), 54 | (1.0, 0.0), 55 | (0.0, 0.0), 56 | (0.0, 1.0), 57 | (1.0, 1.0), 58 | (1.0, 0.0)] 59 | 60 | Mesh3D.draw_type = draw_type 61 | Mesh3D.texture = pygame.image.load(filename) 62 | Mesh3D.int_texture(self) -------------------------------------------------------------------------------- /Chapter09/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | class Grid(): 4 | def __init__(self, interval, halfsize, color): 5 | self.interval = interval 6 | self.halfsize = halfsize 7 | self.color = color 8 | 9 | def draw(self): 10 | glColor3fv(self.color) 11 | glBegin(GL_LINES) 12 | for x in range(-self.halfsize, self.halfsize): 13 | for y in range(-self.halfsize, self.halfsize): 14 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 15 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 16 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 17 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 18 | glEnd() 19 | -------------------------------------------------------------------------------- /Chapter09/LoadMesh.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class LoadMesh(Mesh3D): 4 | def __init__(self, draw_type, model_filename): 5 | self.vertices, self.triangles = self.load_drawing(model_filename) 6 | self.draw_type = draw_type 7 | 8 | def draw(self): 9 | for t in range(0, len(self.triangles), 3): 10 | glBegin(self.draw_type) 11 | glVertex3fv(self.vertices[self.triangles[t]]) 12 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 13 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 14 | glEnd() 15 | glDisable(GL_TEXTURE_2D) 16 | 17 | 18 | def load_drawing(self, filename): 19 | vertices = [] 20 | triangles = [] 21 | with open(filename) as fp: 22 | line = fp.readline() 23 | while line: 24 | if line[:2] == "v ": 25 | vx, vy, vz = [float(value) for value in 26 | line[2:].split()] 27 | vertices.append((vx, vy, vz)) 28 | if line[:2] == "f ": 29 | t1, t2, t3 = [value for value in 30 | line[2:].split()] 31 | triangles.append( 32 | [int(value) for value in t1.split('/')][0] - 1) 33 | triangles.append( 34 | [int(value) for value in t2.split('/')][0] - 1) 35 | triangles.append( 36 | [int(value) for value in t3.split('/')][0] - 1) 37 | line = fp.readline() 38 | return vertices, triangles 39 | 40 | -------------------------------------------------------------------------------- /Chapter09/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | glDisable(GL_TEXTURE_2D) 32 | 33 | def int_texture(self): 34 | self.texID = glGenTextures(1) 35 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 36 | width = self.texture.get_width() 37 | height = self.texture.get_height() 38 | glBindTexture(GL_TEXTURE_2D, self.texID) 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 40 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter09/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | 6 | class Object: 7 | def __init__(self, obj_name): 8 | self.name = obj_name 9 | self.components = [] 10 | 11 | def add_component(self, component): 12 | if isinstance(component, Transform): 13 | self.components.insert(0, self.components) 14 | self.components.append(component) 15 | 16 | def update(self, events = None): 17 | glPushMatrix() 18 | for c in self.components: 19 | if isinstance(c, Transform): 20 | pos = c.get_position() 21 | glTranslatef(pos.x, pos.y, pos.z) 22 | elif isinstance(c, Mesh3D): 23 | c.draw() 24 | elif isinstance(c, Grid): 25 | c.draw() 26 | 27 | glPopMatrix() 28 | 29 | def get_component(self, class_type): 30 | for c in self.components: 31 | if type(c) is class_type: 32 | return c 33 | return None 34 | -------------------------------------------------------------------------------- /Chapter09/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | -------------------------------------------------------------------------------- /Chapter09/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | class Transform: 4 | def __init__(self, position): 5 | self.set_position(position) 6 | 7 | def get_position(self): 8 | return self.position 9 | 10 | def set_position(self, position): 11 | self.position = pygame.math.Vector3(position) 12 | 13 | def move_x(self, amount): 14 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 15 | 16 | def move_y(self, amount): 17 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) 18 | 19 | def move(self, amount: pygame.math.Vector3): 20 | self.position = pygame.math.Vector3(self.position.x + amount.x, 21 | self.position.y + amount.y, 22 | self.position.z + amount.z) -------------------------------------------------------------------------------- /Chapter09/Utils.py: -------------------------------------------------------------------------------- 1 | def map_value(current_min, current_max, new_min, new_max, value): 2 | current_range = current_max - current_min 3 | new_range = new_max - new_min 4 | return new_min + new_range * ((value - current_min) / current_range) -------------------------------------------------------------------------------- /Chapter10/Button.py: -------------------------------------------------------------------------------- 1 | # import math 2 | import pygame.mouse 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from pygame.locals import * 6 | from Settings import * 7 | 8 | class Button: 9 | def __init__(self, screen, position, width, height, color, o_color, p_color, on_click): 10 | self.screen = screen 11 | self.position = position 12 | self.width = width 13 | self.height = height 14 | self.normal_color = color 15 | self.over_color = o_color 16 | self.pressed_color = p_color 17 | self.on_click = on_click 18 | self.mouse_down = False 19 | 20 | 21 | def draw(self, events): 22 | mouse_pos = pygame.mouse.get_pos() 23 | mx = map_value(window_dimensions[0], window_dimensions[1], 24 | gui_dimensions[0], gui_dimensions[1], 25 | mouse_pos[0]) 26 | my = map_value(window_dimensions[2], window_dimensions[3], 27 | gui_dimensions[2], gui_dimensions[3], 28 | mouse_pos[1]) 29 | 30 | glPushMatrix() 31 | glLoadIdentity() 32 | # If the mouse is over the button 33 | if self.position[0] < mx < (self.position[0] + self.width) and self.position[1] < my < (self.position[1] + self.height): 34 | for e in events: 35 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 36 | self.mouse_down = True 37 | self.on_click() 38 | elif e.type == MOUSEBUTTONUP and e.button == 1: 39 | self.mouse_down = False 40 | if self.mouse_down: 41 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 42 | else: 43 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]) 44 | else: 45 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]) 46 | glBegin(GL_POLYGON) 47 | glVertex2f(self.position[0], self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1]) 49 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 50 | glVertex2f(self.position[0], self.position[1] + self.height) 51 | glEnd() 52 | glPopMatrix() -------------------------------------------------------------------------------- /Chapter10/Cube.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class Cube(Mesh3D): 4 | def __init__(self, draw_type, filename): 5 | self.vertices = [(0.5, -0.5, 0.5), 6 | (-0.5, -0.5, 0.5), 7 | (0.5, 0.5, 0.5), 8 | (-0.5, 0.5, 0.5), 9 | (0.5, 0.5, -0.5), 10 | (-0.5, 0.5, -0.5), 11 | (0.5, -0.5, -0.5), 12 | (-0.5, -0.5, -0.5), 13 | (0.5, 0.5, 0.5), 14 | (-0.5, 0.5, 0.5), 15 | (0.5, 0.5, -0.5), 16 | (-0.5, 0.5, -0.5), 17 | (0.5, -0.5, -0.5), 18 | (0.5, -0.5, 0.5), 19 | (-0.5, -0.5, 0.5), 20 | (-0.5, -0.5, -0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, 0.5, 0.5), 23 | (-0.5, 0.5, -0.5), 24 | (-0.5, -0.5, -0.5), 25 | (0.5, -0.5, -0.5), 26 | (0.5, 0.5, -0.5), 27 | (0.5, 0.5, 0.5), 28 | (0.5, -0.5, 0.5)] 29 | 30 | self.triangles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 31 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 32 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 33 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 34 | 35 | self.uvs = [(0.0, 0.0), 36 | (1.0, 0.0), 37 | (0.0, 1.0), 38 | (1.0, 1.0), 39 | (0.0, 1.0), 40 | (1.0, 1.0), 41 | (0.0, 1.0), 42 | (1.0, 1.0), 43 | (0.0, 0.0), 44 | (1.0, 0.0), 45 | (0.0, 0.0), 46 | (1.0, 0.0), 47 | (0.0, 0.0), 48 | (0.0, 1.0), 49 | (1.0, 1.0), 50 | (1.0, 0.0), 51 | (0.0, 0.0), 52 | (0.0, 1.0), 53 | (1.0, 1.0), 54 | (1.0, 0.0), 55 | (0.0, 0.0), 56 | (0.0, 1.0), 57 | (1.0, 1.0), 58 | (1.0, 0.0)] 59 | 60 | Mesh3D.draw_type = draw_type 61 | Mesh3D.texture = pygame.image.load(filename) 62 | Mesh3D.int_texture(self) -------------------------------------------------------------------------------- /Chapter10/Display_Normals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | norm1 = cross_product(p, q) 23 | #norm2 = cross_product(q, p) 24 | nstart = (0, 0, 0) 25 | self.normals.append((nstart, nstart + norm1)) 26 | #self.normals.append((nstart, nstart + norm2)) 27 | 28 | def draw(self): 29 | glColor3fv((0, 1, 0)) 30 | glBegin(GL_LINES) 31 | for i in range(0, len(self.normals)): 32 | start_point = self.normals[i][0] 33 | end_point = self.normals[i][1] 34 | glVertex3fv((start_point[0], start_point[1], 35 | start_point[2])) 36 | glVertex3fv((end_point[0], end_point[1], 37 | end_point[2])) 38 | glEnd() 39 | -------------------------------------------------------------------------------- /Chapter10/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | class Grid(): 4 | def __init__(self, interval, halfsize, color): 5 | self.interval = interval 6 | self.halfsize = halfsize 7 | self.color = color 8 | 9 | def draw(self): 10 | glColor3fv(self.color) 11 | glBegin(GL_LINES) 12 | for x in range(-self.halfsize, self.halfsize): 13 | for y in range(-self.halfsize, self.halfsize): 14 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 15 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 16 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 17 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 18 | glEnd() 19 | -------------------------------------------------------------------------------- /Chapter10/LoadMesh.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class LoadMesh(Mesh3D): 4 | def __init__(self, draw_type, model_filename): 5 | self.vertices, self.triangles = self.load_drawing(model_filename) 6 | self.draw_type = draw_type 7 | 8 | def draw(self): 9 | for t in range(0, len(self.triangles), 3): 10 | glBegin(self.draw_type) 11 | glVertex3fv(self.vertices[self.triangles[t]]) 12 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 13 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 14 | glEnd() 15 | glDisable(GL_TEXTURE_2D) 16 | 17 | 18 | def load_drawing(self, filename): 19 | vertices = [] 20 | triangles = [] 21 | with open(filename) as fp: 22 | line = fp.readline() 23 | while line: 24 | if line[:2] == "v ": 25 | vx, vy, vz = [float(value) for value in 26 | line[2:].split()] 27 | vertices.append((vx, vy, vz)) 28 | if line[:2] == "f ": 29 | t1, t2, t3 = [value for value in 30 | line[2:].split()] 31 | triangles.append( 32 | [int(value) for value in t1.split('/')][0] - 1) 33 | triangles.append( 34 | [int(value) for value in t2.split('/')][0] - 1) 35 | triangles.append( 36 | [int(value) for value in t3.split('/')][0] - 1) 37 | line = fp.readline() 38 | return vertices, triangles 39 | 40 | -------------------------------------------------------------------------------- /Chapter10/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), 5 | (v.x*w.z - v.z*w.x), 6 | (v.x*w.y - v.y*w.x)) 7 | -------------------------------------------------------------------------------- /Chapter10/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | glDisable(GL_TEXTURE_2D) 32 | 33 | def int_texture(self): 34 | self.texID = glGenTextures(1) 35 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 36 | width = self.texture.get_width() 37 | height = self.texture.get_height() 38 | glBindTexture(GL_TEXTURE_2D, self.texID) 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 40 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter10/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from Display_Normals import * 6 | 7 | class Object: 8 | def __init__(self, obj_name): 9 | self.name = obj_name 10 | self.components = [] 11 | 12 | def add_component(self, component): 13 | if isinstance(component, Transform): 14 | self.components.insert(0, self.components) 15 | self.components.append(component) 16 | 17 | def update(self, events = None): 18 | glPushMatrix() 19 | for c in self.components: 20 | if isinstance(c, Transform): 21 | pos = c.get_position() 22 | glTranslatef(pos.x, pos.y, pos.z) 23 | elif isinstance(c, Mesh3D): 24 | c.draw() 25 | elif isinstance(c, Grid): 26 | c.draw() 27 | elif isinstance(c,DisplayNormals): 28 | c.draw() 29 | 30 | glPopMatrix() 31 | 32 | def get_component(self, class_type): 33 | for c in self.components: 34 | if type(c) is class_type: 35 | return c 36 | return None 37 | -------------------------------------------------------------------------------- /Chapter10/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | -------------------------------------------------------------------------------- /Chapter10/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | class Transform: 4 | def __init__(self, position): 5 | self.set_position(position) 6 | 7 | def get_position(self): 8 | return self.position 9 | 10 | def set_position(self, position): 11 | self.position = pygame.math.Vector3(position) 12 | 13 | def move_x(self, amount): 14 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 15 | 16 | def move_y(self, amount): 17 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) 18 | 19 | def move(self, amount: pygame.math.Vector3): 20 | self.position = pygame.math.Vector3(self.position.x + amount.x, 21 | self.position.y + amount.y, 22 | self.position.z + amount.z) -------------------------------------------------------------------------------- /Chapter10/Utils.py: -------------------------------------------------------------------------------- 1 | def map_value(current_min, current_max, new_min, new_max, value): 2 | current_range = current_max - current_min 3 | new_range = new_max - new_min 4 | return new_min + new_range * ((value - current_min) / current_range) -------------------------------------------------------------------------------- /Chapter11/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter11/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter11/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter11/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter11/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter11/NormalLights.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | from Object import * 4 | from pygame.locals import * 5 | from OpenGL.GLU import * 6 | from LoadMesh import * 7 | from Cube import * 8 | 9 | pygame.init() 10 | screen_width = math.fabs(window_dimensions[1] - window_dimensions[0]) 11 | screen_height = math.fabs(window_dimensions[3] - window_dimensions[2]) 12 | pygame.display.set_caption('OpenGL in Python') 13 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 14 | done = False 15 | white = pygame.Color(255, 255, 255) 16 | 17 | objects_3d = [] 18 | objects_2d = [] 19 | 20 | leaf = Object("Leaf") 21 | leaf.add_component(Transform((0, 0, -3))) 22 | leaf.add_component(LoadMesh(GL_TRIANGLES, "../models/cube.obj")) 23 | 24 | objects_3d.append(leaf) 25 | 26 | clock = pygame.time.Clock() 27 | fps = 30 28 | 29 | def set_2d(): 30 | glMatrixMode(GL_PROJECTION) 31 | glLoadIdentity() # reset projection matrix 32 | gluOrtho2D(gui_dimensions[0], gui_dimensions[1], 33 | gui_dimensions[3], gui_dimensions[2]) 34 | glMatrixMode(GL_MODELVIEW) 35 | glLoadIdentity() # reset modelview matrix 36 | glViewport(0, 0, screen.get_width(), screen.get_height()) 37 | 38 | def set_3d(): 39 | glMatrixMode(GL_PROJECTION) 40 | glLoadIdentity() 41 | gluPerspective(60, (screen_width / screen_height), 0.1, 100.0) 42 | glMatrixMode(GL_MODELVIEW) 43 | glLoadIdentity() 44 | glViewport(0, 0, screen.get_width(), screen.get_height()) 45 | glEnable(GL_DEPTH_TEST) 46 | glEnable(GL_LIGHTING) 47 | glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 0)) 48 | glLightfv(GL_LIGHT0, GL_AMBIENT, (1, 0, 1, 1)) 49 | glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 0, 1)) 50 | glLightfv(GL_LIGHT0, GL_SPECULAR, (0, 1, 0, 1)) 51 | glEnable(GL_LIGHT0) 52 | 53 | while not done: 54 | events = pygame.event.get() 55 | for event in events: 56 | if event.type == pygame.QUIT: 57 | done = True 58 | 59 | glPushMatrix() 60 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 61 | 62 | set_3d() 63 | for o in objects_3d: 64 | o.update(events) 65 | 66 | set_2d() 67 | for o in objects_2d: 68 | o.update(events) 69 | 70 | glPopMatrix() 71 | pygame.display.flip() 72 | dt = clock.tick(fps) 73 | pygame.quit() 74 | -------------------------------------------------------------------------------- /Chapter11/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | 7 | 8 | class Object: 9 | def __init__(self, obj_name): 10 | self.name = obj_name 11 | self.components = [] 12 | self.scene_angle = 45 13 | 14 | def add_component(self, component): 15 | if isinstance(component, Transform): 16 | self.components.insert(0, self.components) 17 | self.components.append(component) 18 | 19 | def get_component(self, class_type): 20 | for c in self.components: 21 | if type(c) is class_type: 22 | return c 23 | return None 24 | 25 | 26 | def update(self, events = None): 27 | glPushMatrix() 28 | for c in self.components: 29 | if isinstance(c, Transform): 30 | pos = c.get_position() 31 | glTranslatef(pos.x, pos.y, pos.z) 32 | self.scene_angle += 2 33 | glRotate(self.scene_angle, 0, 1, 0) 34 | elif isinstance(c, Mesh3D): 35 | glColor(1, 1, 1) 36 | c.draw() 37 | elif isinstance(c, Grid): 38 | c.draw() 39 | elif isinstance(c, DisplayNormals): 40 | c.draw() 41 | elif isinstance(c, Button): 42 | c.draw(events) 43 | glPopMatrix() 44 | -------------------------------------------------------------------------------- /Chapter11/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter11/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | 4 | class Transform: 5 | def __init__(self, position): 6 | self.position = pygame.math.Vector3(position) 7 | 8 | def get_position(self): 9 | return self.position 10 | 11 | def set_position(self, position): 12 | self.position = pygame.math.Vector3(position) 13 | 14 | def move_x(self, amount): 15 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 16 | 17 | def move_y(self, amount): 18 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) 19 | 20 | def move(self, amount: pygame.math.Vector3): 21 | self.position = pygame.math.Vector3(self.position.x + amount.x, 22 | self.position.y + amount.y, 23 | self.position.z + amount.z) 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter11/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter11/models/cube.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | mtllib cube.mtl 4 | g default 5 | v -0.500000 -0.500000 0.500000 6 | v 0.500000 -0.500000 0.500000 7 | v -0.500000 0.500000 0.500000 8 | v 0.500000 0.500000 0.500000 9 | v -0.500000 0.500000 -0.500000 10 | v 0.500000 0.500000 -0.500000 11 | v -0.500000 -0.500000 -0.500000 12 | v 0.500000 -0.500000 -0.500000 13 | vt 0.001992 0.001992 14 | vt 0.998008 0.001992 15 | vt 0.001992 0.998008 16 | vt 0.998008 0.998008 17 | vt 0.001992 0.001992 18 | vt 0.998008 0.001992 19 | vt 0.001992 0.998008 20 | vt 0.998008 0.998008 21 | vt 0.001992 0.001992 22 | vt 0.998008 0.001992 23 | vt 0.001992 0.998008 24 | vt 0.998008 0.998008 25 | vt 0.001992 0.001992 26 | vt 0.998008 0.001992 27 | vt 0.001992 0.998008 28 | vt 0.998008 0.998008 29 | vt 0.001992 0.001992 30 | vt 0.998008 0.001992 31 | vt 0.001992 0.998008 32 | vt 0.998008 0.998008 33 | vt 0.001992 0.001992 34 | vt 0.998008 0.001992 35 | vt 0.001992 0.998008 36 | vt 0.998008 0.998008 37 | vn 0.000000 0.000000 1.000000 38 | vn 0.000000 0.000000 1.000000 39 | vn 0.000000 0.000000 1.000000 40 | vn 0.000000 0.000000 1.000000 41 | vn 0.000000 1.000000 0.000000 42 | vn 0.000000 1.000000 0.000000 43 | vn 0.000000 1.000000 0.000000 44 | vn 0.000000 1.000000 0.000000 45 | vn 0.000000 0.000000 -1.000000 46 | vn 0.000000 0.000000 -1.000000 47 | vn 0.000000 0.000000 -1.000000 48 | vn 0.000000 0.000000 -1.000000 49 | vn 0.000000 -1.000000 0.000000 50 | vn 0.000000 -1.000000 0.000000 51 | vn 0.000000 -1.000000 0.000000 52 | vn 0.000000 -1.000000 0.000000 53 | vn 1.000000 0.000000 0.000000 54 | vn 1.000000 0.000000 0.000000 55 | vn 1.000000 0.000000 0.000000 56 | vn 1.000000 0.000000 0.000000 57 | vn -1.000000 0.000000 0.000000 58 | vn -1.000000 0.000000 0.000000 59 | vn -1.000000 0.000000 0.000000 60 | vn -1.000000 0.000000 0.000000 61 | s 1 62 | g pCube1 63 | usemtl phong2SG 64 | f 1/21/1 2/22/2 3/23/3 65 | f 3/23/3 2/22/2 4/24/4 66 | s 2 67 | f 3/5/5 4/6/6 5/7/7 68 | f 5/7/7 4/6/6 6/8/8 69 | s 3 70 | f 5/9/9 6/10/10 7/11/11 71 | f 7/11/11 6/10/10 8/12/12 72 | s 4 73 | f 7/17/13 8/18/14 1/19/15 74 | f 1/19/15 8/18/14 2/20/16 75 | s 5 76 | f 2/1/17 8/2/18 4/3/19 77 | f 4/3/19 8/2/18 6/4/20 78 | s 6 79 | f 7/13/21 1/14/22 5/15/23 80 | f 5/15/23 1/14/22 3/16/24 81 | -------------------------------------------------------------------------------- /Chapter11/startercode/ExploreNormals.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | from Object import * 4 | from DisplayNormals import * 5 | from pygame.locals import * 6 | from OpenGL.GLU import * 7 | from LoadMesh import * 8 | 9 | pygame.init() 10 | screen_width = math.fabs(window_dimensions[1] - window_dimensions[0]) 11 | screen_height = math.fabs(window_dimensions[3] - window_dimensions[2]) 12 | pygame.display.set_caption('OpenGL in Python') 13 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 14 | done = False 15 | white = pygame.Color(255, 255, 255) 16 | 17 | objects_3d = [] 18 | objects_2d = [] 19 | 20 | mesh = Object("Plane") 21 | mesh.add_component(Transform((0, 0, -1.5))) 22 | mesh.add_component(LoadMesh(GL_LINE_LOOP, "models/planesm.obj")) 23 | mesh.add_component(DisplayNormals(mesh.get_component(LoadMesh).vertices, mesh.get_component(LoadMesh).triangles)) 24 | 25 | objects_3d.append(mesh) 26 | 27 | clock = pygame.time.Clock() 28 | fps = 30 29 | 30 | def set_2d(): 31 | glMatrixMode(GL_PROJECTION) 32 | glLoadIdentity() # reset projection matrix 33 | gluOrtho2D(gui_dimensions[0], gui_dimensions[1], 34 | gui_dimensions[3], gui_dimensions[2]) 35 | glMatrixMode(GL_MODELVIEW) 36 | glLoadIdentity() # reset modelview matrix 37 | glViewport(0, 0, screen.get_width(), screen.get_height()) 38 | 39 | def set_3d(): 40 | glMatrixMode(GL_PROJECTION) 41 | glLoadIdentity() 42 | gluPerspective(60, (screen_width / screen_height), 0.1, 100.0) 43 | glMatrixMode(GL_MODELVIEW) 44 | glLoadIdentity() 45 | glViewport(0, 0, screen.get_width(), screen.get_height()) 46 | glEnable(GL_DEPTH_TEST) 47 | 48 | while not done: 49 | events = pygame.event.get() 50 | for event in events: 51 | if event.type == pygame.QUIT: 52 | done = True 53 | 54 | glPushMatrix() 55 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 56 | 57 | set_3d() 58 | for o in objects_3d: 59 | o.update(events) 60 | 61 | set_2d() 62 | for o in objects_2d: 63 | o.update(events) 64 | 65 | glPopMatrix() 66 | pygame.display.flip() 67 | dt = clock.tick(fps) 68 | pygame.quit() 69 | -------------------------------------------------------------------------------- /Chapter12/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter12/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter12/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter12/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter12/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter12/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | 7 | 8 | class Object: 9 | def __init__(self, obj_name): 10 | self.name = obj_name 11 | self.components = [] 12 | self.scene_angle = 45 13 | 14 | def add_component(self, component): 15 | if isinstance(component, Transform): 16 | self.components.insert(0, self.components) 17 | self.components.append(component) 18 | 19 | def get_component(self, class_type): 20 | for c in self.components: 21 | if type(c) is class_type: 22 | return c 23 | return None 24 | 25 | 26 | def update(self, events = None): 27 | glPushMatrix() 28 | for c in self.components: 29 | if isinstance(c, Transform): 30 | pos = c.get_position() 31 | scale = c.get_scale() 32 | rot_angle = c.get_rotation_angle() 33 | rot_axis = c.get_rotation_axis() 34 | 35 | glTranslatef(pos.x, pos.y, pos.z) 36 | glScalef(scale.x, scale.y, scale.z) 37 | glRotated(rot_angle, rot_axis.x, rot_axis.y, rot_axis.z) 38 | 39 | 40 | elif isinstance(c, Mesh3D): 41 | glColor(1, 1, 1) 42 | c.draw() 43 | elif isinstance(c, Grid): 44 | c.draw() 45 | elif isinstance(c, DisplayNormals): 46 | c.draw() 47 | elif isinstance(c, Button): 48 | c.draw(events) 49 | glPopMatrix() 50 | -------------------------------------------------------------------------------- /Chapter12/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter12/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | 4 | class Transform: 5 | def __init__(self, position=pygame.math.Vector3(0, 0, 0), scale=pygame.math.Vector3(1, 1, 1)): 6 | self.position = pygame.math.Vector3(position) 7 | self.scale = pygame.math.Vector3(scale) 8 | self.rotation_angle = 0 9 | self.rotation_axis = pygame.math.Vector3(0, 1, 0) 10 | 11 | def get_position(self): 12 | return self.position 13 | 14 | def set_position(self, position): 15 | self.position = pygame.math.Vector3(position) 16 | 17 | def move_x(self, amount): 18 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 19 | 20 | def move_y(self, amount): 21 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) 22 | 23 | def move(self, amount: pygame.math.Vector3): 24 | self.position = pygame.math.Vector3(self.position.x + amount.x, 25 | self.position.y + amount.y, 26 | self.position.z + amount.z) 27 | 28 | def get_scale(self): 29 | return self.scale 30 | 31 | def update_scale(self, amount: pygame.math.Vector3): 32 | self.scale.x *= amount.x 33 | self.scale.y *= amount.y 34 | self.scale.z *= amount.z 35 | 36 | def set_scale(self, amount: pygame.math.Vector3): 37 | self.scale = amount 38 | 39 | def get_rotation_angle(self): 40 | return self.rotation_angle 41 | 42 | def get_rotation_axis(self): 43 | return self.rotation_axis 44 | 45 | def set_rotation_axis(self, amount: pygame.math.Vector3): 46 | self.rotation_axis = amount 47 | 48 | def update_rotation_angle(self, amount): 49 | self.rotation_angle += amount 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Chapter12/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter13/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter13/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter13/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter13/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter13/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter13/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | 7 | 8 | class Object: 9 | def __init__(self, obj_name): 10 | self.name = obj_name 11 | self.components = [] 12 | self.scene_angle = 45 13 | 14 | def add_component(self, component): 15 | if isinstance(component, Transform): 16 | self.components.insert(0, self.components) 17 | self.components.append(component) 18 | 19 | def get_component(self, class_type): 20 | for c in self.components: 21 | if type(c) is class_type: 22 | return c 23 | return None 24 | 25 | 26 | def update(self, events = None): 27 | glPushMatrix() 28 | for c in self.components: 29 | if isinstance(c, Transform): 30 | pos = c.get_position() 31 | scale = c.get_scale() 32 | rot_angle = c.get_rotation_angle() 33 | rot_axis = c.get_rotation_axis() 34 | 35 | glTranslatef(pos.x, pos.y, pos.z) 36 | glRotated(rot_angle, rot_axis.x, rot_axis.y, rot_axis.z) 37 | glScalef(scale.x, scale.y, scale.z) 38 | mv = glGetDoublev(GL_MODELVIEW_MATRIX) 39 | print("MV: ") 40 | print(mv) 41 | 42 | elif isinstance(c, Mesh3D): 43 | glColor(1, 1, 1) 44 | c.draw() 45 | elif isinstance(c, Grid): 46 | c.draw() 47 | elif isinstance(c, DisplayNormals): 48 | c.draw() 49 | elif isinstance(c, Button): 50 | c.draw(events) 51 | glPopMatrix() 52 | -------------------------------------------------------------------------------- /Chapter13/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter13/Transform.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | 4 | class Transform: 5 | def __init__(self, position=pygame.math.Vector3(0, 0, 0), scale=pygame.math.Vector3(1, 1, 1)): 6 | self.position = pygame.math.Vector3(position) 7 | self.scale = pygame.math.Vector3(scale) 8 | self.rotation_angle = 0 9 | self.rotation_axis = pygame.math.Vector3(0, 1, 0) 10 | 11 | def get_position(self): 12 | return self.position 13 | 14 | def set_position(self, position): 15 | self.position = pygame.math.Vector3(position) 16 | 17 | def move_x(self, amount): 18 | self.position = pygame.math.Vector3(self.position.x + amount, self.position.y, self.position.z) 19 | 20 | def move_y(self, amount): 21 | self.position = pygame.math.Vector3(self.position.x, self.position.y + amount, self.position.z) 22 | 23 | def move(self, amount: pygame.math.Vector3): 24 | self.position = pygame.math.Vector3(self.position.x + amount.x, 25 | self.position.y + amount.y, 26 | self.position.z + amount.z) 27 | 28 | def get_scale(self): 29 | return self.scale 30 | 31 | def update_scale(self, amount: pygame.math.Vector3): 32 | self.scale.x *= amount.x 33 | self.scale.y *= amount.y 34 | self.scale.z *= amount.z 35 | 36 | def set_scale(self, amount: pygame.math.Vector3): 37 | self.scale = amount 38 | 39 | def get_rotation_angle(self): 40 | return self.rotation_angle 41 | 42 | def get_rotation_axis(self): 43 | return self.rotation_axis 44 | 45 | def set_rotation_axis(self, amount: pygame.math.Vector3): 46 | self.rotation_axis = amount 47 | 48 | def update_rotation_angle(self, amount): 49 | self.rotation_angle += amount 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Chapter13/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter14/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter14/Camera.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import math 3 | import numpy as np 4 | 5 | 6 | class Camera: 7 | def __init__(self, fovy, aspect, near, far): 8 | f = 1/math.tan(math.radians(fovy/2)) 9 | a = f/aspect 10 | b = f 11 | c = (far + near) / (near - far) 12 | d = 2 * near * far / (near - far) 13 | self.PPM = np.matrix([ 14 | [a, 0, 0, 0], 15 | [0, b, 0, 0], 16 | [0, 0, c, -1], 17 | [0, 0, d, 0] 18 | ]) 19 | self.VM = np.identity(4) 20 | 21 | def get_VM(self): 22 | return self.VM 23 | 24 | def get_PPM(self): 25 | return self.PPM 26 | 27 | def get_position(self): 28 | position = pygame.Vector3(self.VM[0, 3], self.VM[1, 3], self.VM[2, 3]) 29 | return position 30 | 31 | def update_position(self, position: pygame.Vector3): 32 | self.VM = self.VM @ np.matrix([[1, 0, 0, 0], 33 | [0, 1, 0, 0], 34 | [0, 0, 1, 0], 35 | [position.x, position.y, position.z, 1]]) 36 | 37 | def update(self): 38 | key = pygame.key.get_pressed() 39 | if key[pygame.K_w]: 40 | self.update_position(self.get_position() + pygame.Vector3(0, 0, 0.01)) 41 | if key[pygame.K_s]: 42 | self.update_position(self.get_position() + pygame.Vector3(0, 0, -0.01)) 43 | 44 | -------------------------------------------------------------------------------- /Chapter14/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter14/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter14/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter14/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter14/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter14/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | from Camera import * 7 | 8 | 9 | class Object: 10 | def __init__(self, obj_name): 11 | self.name = obj_name 12 | self.components = [] 13 | self.scene_angle = 45 14 | 15 | def add_component(self, component): 16 | if isinstance(component, Transform): 17 | self.components.insert(0, self.components) 18 | self.components.append(component) 19 | 20 | def get_component(self, class_type): 21 | for c in self.components: 22 | if type(c) is class_type: 23 | return c 24 | return None 25 | 26 | 27 | def update(self, camera: Camera, events = None): 28 | glPushMatrix() 29 | for c in self.components: 30 | if isinstance(c, Transform): 31 | glLoadMatrixf(c.get_MVM() * camera.get_VM()) 32 | #mv = glGetDoublev(GL_MODELVIEW_MATRIX) 33 | #print("MV: ") 34 | #print(mv) 35 | 36 | elif isinstance(c, Mesh3D): 37 | glColor(1, 1, 1) 38 | c.draw() 39 | elif isinstance(c, Grid): 40 | c.draw() 41 | elif isinstance(c, DisplayNormals): 42 | c.draw() 43 | elif isinstance(c, Button): 44 | c.draw(events) 45 | glPopMatrix() 46 | -------------------------------------------------------------------------------- /Chapter14/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter14/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter15/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter15/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter15/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter15/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter15/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter15/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter15/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | from Camera import * 7 | 8 | 9 | class Object: 10 | def __init__(self, obj_name): 11 | self.name = obj_name 12 | self.components = [] 13 | self.scene_angle = 45 14 | 15 | def add_component(self, component): 16 | if isinstance(component, Transform): 17 | self.components.insert(0, self.components) 18 | self.components.append(component) 19 | 20 | def get_component(self, class_type): 21 | for c in self.components: 22 | if type(c) is class_type: 23 | return c 24 | return None 25 | 26 | 27 | def update(self, camera: Camera, events = None): 28 | glPushMatrix() 29 | for c in self.components: 30 | if isinstance(c, Transform): 31 | glLoadMatrixf(c.get_MVM() * camera.get_VM()) 32 | #mv = glGetDoublev(GL_MODELVIEW_MATRIX) 33 | #print("MV: ") 34 | #print(mv) 35 | 36 | elif isinstance(c, Mesh3D): 37 | glColor(1, 1, 1) 38 | c.draw() 39 | elif isinstance(c, Grid): 40 | c.draw() 41 | elif isinstance(c, DisplayNormals): 42 | c.draw() 43 | elif isinstance(c, Button): 44 | c.draw(events) 45 | glPopMatrix() 46 | -------------------------------------------------------------------------------- /Chapter15/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter15/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter16/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter16/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter16/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter16/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter16/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter16/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter16/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from DisplayNormals import * 6 | from Camera import * 7 | 8 | 9 | class Object: 10 | def __init__(self, obj_name): 11 | self.name = obj_name 12 | self.components = [] 13 | self.scene_angle = 45 14 | 15 | def add_component(self, component): 16 | if isinstance(component, Transform): 17 | self.components.insert(0, self.components) 18 | self.components.append(component) 19 | 20 | def get_component(self, class_type): 21 | for c in self.components: 22 | if type(c) is class_type: 23 | return c 24 | return None 25 | 26 | 27 | def update(self, camera: Camera, events = None): 28 | glPushMatrix() 29 | for c in self.components: 30 | if isinstance(c, Transform): 31 | glLoadMatrixf(c.get_MVM() * camera.get_VM()) 32 | #mv = glGetDoublev(GL_MODELVIEW_MATRIX) 33 | #print("MV: ") 34 | #print(mv) 35 | print("projection") 36 | print(camera.PPM) 37 | print("view") 38 | print(camera.get_VM()) 39 | print("model") 40 | print(c.get_MVM()) 41 | 42 | elif isinstance(c, Mesh3D): 43 | glColor(1, 1, 1) 44 | c.draw() 45 | elif isinstance(c, Grid): 46 | c.draw() 47 | elif isinstance(c, DisplayNormals): 48 | c.draw() 49 | elif isinstance(c, Button): 50 | c.draw(events) 51 | glPopMatrix() 52 | -------------------------------------------------------------------------------- /Chapter16/Quaternion.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import pygame 3 | import math 4 | import numpy as np 5 | import sys 6 | 7 | 8 | class Quaternion: 9 | def __init__(self, vector=None, axis: pygame.Vector3 = None, angle: float = None): 10 | if vector is not None: 11 | self.w = vector[0] 12 | self.x = vector[1] 13 | self.y = vector[2] 14 | self.z = vector[3] 15 | else: 16 | axis = axis.normalize() 17 | sin_angle = math.sin(math.radians(angle/2.0)) 18 | cos_angle = math.cos(math.radians(angle/2.0)) 19 | self.w = cos_angle 20 | self.x = axis.x * sin_angle 21 | self.y = axis.y * sin_angle 22 | self.z = axis.z * sin_angle 23 | self.normalise() 24 | 25 | def __mul__(self, other: Quaternion): 26 | v1 = pygame.Vector3(self.x, self.y, self.z) 27 | v2 = pygame.Vector3(other.x, other.y, other.z) 28 | cross = v1.cross(v2) 29 | dot = v1.dot(v2) 30 | v3 = cross + (self.w * v2) + (other.w * v1) 31 | result = Quaternion(vector=(self.w * other.w - dot, v3.x, v3.y, v3.z)) 32 | return result 33 | 34 | def normalise(self): 35 | l = math.sqrt(self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z) 36 | #print("length: " + l.__str__()) 37 | if l > sys.float_info.epsilon: 38 | self.w /= l 39 | self.x /= l 40 | self.y /= l 41 | self.z /= l 42 | 43 | 44 | 45 | def get_matrix(self): 46 | x2 = self.x + self.x 47 | y2 = self.y + self.y 48 | z2 = self.z + self.z 49 | xx2 = self.x * x2 50 | xy2 = self.x * y2 51 | xz2 = self.x * z2 52 | yy2 = self.y * y2 53 | yz2 = self.y * z2 54 | zz2 = self.z * z2 55 | wx2 = self.w * x2 56 | wy2 = self.w * y2 57 | wz2 = self.w * z2 58 | 59 | return np.matrix([ 60 | [1 - (yy2 + zz2), xy2 + wz2, xz2 - wy2, 0], 61 | [xy2 - wz2, 1 - (xx2 + zz2), yz2 + wx2, 0], 62 | [xz2 + wy2, yz2 - wx2, 1 - (xx2 + yy2), 0], 63 | [0, 0, 0, 1] 64 | ]) 65 | 66 | #return np.matrix([ 67 | # [1 - (yy2 + zz2), xy2 - wz2, xz2 + wy2, 0], 68 | # [xy2 + wz2, 1 - (xx2 + zz2), yz2 - wx2, 0], 69 | # [xz2 - wy2, yz2 + wx2, 1 - (xx2 + yy2), 0], 70 | # [0, 0, 0, 1] 71 | #]) 72 | 73 | -------------------------------------------------------------------------------- /Chapter16/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter16/Utils.py: -------------------------------------------------------------------------------- 1 | 2 | def map_value(current_min, current_max, new_min, new_max, value): 3 | current_range = current_max - current_min 4 | new_range = new_max - new_min 5 | return new_min + new_range * ((value-current_min)/current_range) 6 | 7 | -------------------------------------------------------------------------------- /Chapter17/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter17/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter17/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter17/GraphicsData.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | class GraphicsData(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.buffer_ref = glGenBuffers(1) 9 | self.load() 10 | 11 | def load(self): 12 | data = np.array(self.data, np.float32) 13 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 14 | glBufferData(GL_ARRAY_BUFFER, data.ravel(), GL_STATIC_DRAW) 15 | 16 | def create_variable(self, program_id, variable_name): 17 | variable_id = glGetAttribLocation(program_id, variable_name) 18 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 19 | if self.data_type == "vec3": 20 | glVertexAttribPointer(variable_id, 3, GL_FLOAT, False, 0, None) 21 | elif self.data_type == "vec2": 22 | glVertexAttribPointer(variable_id, 2, GL_FLOAT, False, 0, None) 23 | 24 | glEnableVertexAttribArray(variable_id) -------------------------------------------------------------------------------- /Chapter17/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter17/Material.py: -------------------------------------------------------------------------------- 1 | from Utils import * 2 | 3 | class Material: 4 | def __init__(self, vertex_shader, fragment_shader): 5 | self.program_id = create_program(open(vertex_shader).read(), open(fragment_shader).read()) 6 | 7 | def use(self): 8 | glUseProgram(self.program_id) 9 | 10 | -------------------------------------------------------------------------------- /Chapter17/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter17/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter17/Object.py: -------------------------------------------------------------------------------- 1 | from LoadMesh import * 2 | from Camera import * 3 | from Material import * 4 | from Uniform import * 5 | 6 | 7 | class Object: 8 | def __init__(self, obj_name): 9 | self.name = obj_name 10 | self.components = [] 11 | self.material = None 12 | self.vao_ref = glGenVertexArrays(1) 13 | glBindVertexArray(self.vao_ref) 14 | 15 | def add_component(self, component): 16 | if isinstance(component, Transform): 17 | self.components.insert(0, self.components) 18 | if isinstance(component, Material): 19 | self.material = component 20 | self.components.append(component) 21 | 22 | def get_component(self, class_type): 23 | for c in self.components: 24 | if type(c) is class_type: 25 | return c 26 | return None 27 | 28 | 29 | def update(self, camera: Camera, events = None): 30 | self.material.use() 31 | for c in self.components: 32 | if isinstance(c, Transform): 33 | projection = Uniform("mat4", camera.get_PPM()) 34 | projection.find_variable(self.material.program_id, "projection_mat") 35 | projection.load() 36 | 37 | lookat = Uniform("mat4", camera.get_VM()) 38 | lookat.find_variable(self.material.program_id, "view_mat") 39 | lookat.load() 40 | 41 | transformation = Uniform("mat4", c.get_MVM()) 42 | transformation.find_variable(self.material.program_id, "model_mat") 43 | transformation.load() 44 | 45 | elif isinstance(c, LoadMesh): 46 | c.draw() 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Chapter17/Quaternion.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import pygame 3 | import math 4 | import numpy as np 5 | import sys 6 | 7 | 8 | class Quaternion: 9 | def __init__(self, vector=None, axis: pygame.Vector3 = None, angle: float = None): 10 | if vector is not None: 11 | self.w = vector[0] 12 | self.x = vector[1] 13 | self.y = vector[2] 14 | self.z = vector[3] 15 | else: 16 | axis = axis.normalize() 17 | sin_angle = math.sin(math.radians(angle/2.0)) 18 | cos_angle = math.cos(math.radians(angle/2.0)) 19 | self.w = cos_angle 20 | self.x = axis.x * sin_angle 21 | self.y = axis.y * sin_angle 22 | self.z = axis.z * sin_angle 23 | self.normalise() 24 | 25 | def __mul__(self, other: Quaternion): 26 | v1 = pygame.Vector3(self.x, self.y, self.z) 27 | v2 = pygame.Vector3(other.x, other.y, other.z) 28 | cross = v1.cross(v2) 29 | dot = v1.dot(v2) 30 | v3 = cross + (self.w * v2) + (other.w * v1) 31 | result = Quaternion(vector=(self.w * other.w - dot, v3.x, v3.y, v3.z)) 32 | return result 33 | 34 | def normalise(self): 35 | l = math.sqrt(self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z) 36 | #print("length: " + l.__str__()) 37 | if l > sys.float_info.epsilon: 38 | self.w /= l 39 | self.x /= l 40 | self.y /= l 41 | self.z /= l 42 | 43 | 44 | 45 | def get_matrix(self): 46 | x2 = self.x + self.x 47 | y2 = self.y + self.y 48 | z2 = self.z + self.z 49 | xx2 = self.x * x2 50 | xy2 = self.x * y2 51 | xz2 = self.x * z2 52 | yy2 = self.y * y2 53 | yz2 = self.y * z2 54 | zz2 = self.z * z2 55 | wx2 = self.w * x2 56 | wy2 = self.w * y2 57 | wz2 = self.w * z2 58 | 59 | return np.matrix([ 60 | [1 - (yy2 + zz2), xy2 + wz2, xz2 - wy2, 0], 61 | [xy2 - wz2, 1 - (xx2 + zz2), yz2 + wx2, 0], 62 | [xz2 + wy2, yz2 - wx2, 1 - (xx2 + yy2), 0], 63 | [0, 0, 0, 1] 64 | ]) 65 | 66 | #return np.matrix([ 67 | # [1 - (yy2 + zz2), xy2 - wz2, xz2 + wy2, 0], 68 | # [xy2 + wz2, 1 - (xx2 + zz2), yz2 - wx2, 0], 69 | # [xz2 - wy2, yz2 + wx2, 1 - (xx2 + yy2), 0], 70 | # [0, 0, 0, 1] 71 | #]) 72 | 73 | -------------------------------------------------------------------------------- /Chapter17/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter17/ShaderTeapot.py: -------------------------------------------------------------------------------- 1 | from Object import * 2 | from pygame.locals import * 3 | from Camera import * 4 | from LoadMesh import * 5 | from Material import * 6 | from Settings import * 7 | 8 | pygame.init() 9 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1) 10 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES, 4) 11 | pygame.display.gl_set_attribute(pygame.GL_CONTEXT_PROFILE_MASK, pygame.GL_CONTEXT_PROFILE_CORE) 12 | pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 32) 13 | screen_width = math.fabs(window_dimensions[1] - window_dimensions[0]) 14 | screen_height = math.fabs(window_dimensions[3] - window_dimensions[2]) 15 | pygame.display.set_caption('OpenGL in Python') 16 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 17 | done = False 18 | white = pygame.Color(255, 255, 255) 19 | glDisable(GL_CULL_FACE) 20 | glEnable(GL_DEPTH_TEST) 21 | glEnable(GL_BLEND) 22 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 23 | objects_3d = [] 24 | camera = Camera(60, (screen_width / screen_height), 0.01, 10000.0) 25 | 26 | quat_teapot = Object("Teapot") 27 | quat_teapot.add_component(Transform()) 28 | mat = Material("shaders/vertexcolvert.vs", "shaders/vertexcolfrag.vs") 29 | quat_teapot.add_component(LoadMesh(quat_teapot.vao_ref, mat, GL_LINE_LOOP, "../models/teapotSM.obj")) 30 | quat_teapot.add_component(mat) 31 | quat_trans: Transform = quat_teapot.get_component(Transform) 32 | quat_trans.update_position(pygame.Vector3(0, 0, 0)) 33 | 34 | objects_3d.append(quat_teapot) 35 | 36 | clock = pygame.time.Clock() 37 | fps = 30 38 | 39 | pygame.event.set_grab(True) 40 | pygame.mouse.set_visible(False) 41 | while not done: 42 | events = pygame.event.get() 43 | for event in events: 44 | if event.type == pygame.QUIT: 45 | done = True 46 | if event.type == KEYDOWN: 47 | if event.key == K_ESCAPE: 48 | pygame.mouse.set_visible(True) 49 | pygame.event.set_grab(False) 50 | if event.key == K_SPACE: 51 | pygame.mouse.set_visible(False) 52 | pygame.event.set_grab(True) 53 | 54 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 55 | camera.update() 56 | for o in objects_3d: 57 | o.update(camera, events) 58 | 59 | pygame.display.flip() 60 | dt = clock.tick(fps) 61 | pygame.quit() 62 | -------------------------------------------------------------------------------- /Chapter17/Uniform.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Uniform(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.variable_id = None 9 | 10 | def find_variable(self, program_id, variable_name): 11 | self.variable_id = glGetUniformLocation(program_id, variable_name) 12 | 13 | def load(self): 14 | if self.data_type == "vec3": 15 | glUniform3f(self.variable_id, self.data[0], self.data[1], self.data[2]) 16 | elif self.data_type == "mat4": 17 | glUniformMatrix4fv(self.variable_id, 1, GL_TRUE, self.data) 18 | elif self.data_type == "sampler2D": 19 | texture_obj, texture_unit = self.data 20 | glActiveTexture(GL_TEXTURE0 + texture_unit) 21 | glBindTexture(GL_TEXTURE_2D, texture_obj) 22 | glUniform1i(self.variable_id, texture_unit) -------------------------------------------------------------------------------- /Chapter17/Utils.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | def map_value(current_min, current_max, new_min, new_max, value): 5 | current_range = current_max - current_min 6 | new_range = new_max - new_min 7 | return new_min + new_range * ((value-current_min)/current_range) 8 | 9 | def compile_shader(shader_type, shader_source): 10 | shader_id = glCreateShader(shader_type) 11 | glShaderSource(shader_id, shader_source) 12 | glCompileShader(shader_id) 13 | compile_success = glGetShaderiv(shader_id, GL_COMPILE_STATUS) 14 | if not compile_success: 15 | error_message = glGetShaderInfoLog(shader_id) 16 | glDeleteShader(shader_id) 17 | error_message = "\n" + error_message.decode("utf-8") 18 | raise Exception(error_message) 19 | return shader_id 20 | 21 | def create_program(vertex_shader_code, fragment_shader_code): 22 | vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader_code) 23 | fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_code) 24 | program_id = glCreateProgram() 25 | glAttachShader(program_id, vertex_shader_id) 26 | glAttachShader(program_id, fragment_shader_id) 27 | glLinkProgram(program_id) 28 | link_success = glGetProgramiv(program_id, GL_LINK_STATUS) 29 | if not link_success: 30 | info = glGetProgramInfoLog(program_id) 31 | raise RuntimeError(info) 32 | glDeleteShader(vertex_shader_id) 33 | glDeleteShader(fragment_shader_id) 34 | return program_id 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Chapter17/shaders/vertexcolfrag.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | out vec4 frag_color; 3 | void main() 4 | { 5 | frag_color = vec4(1, 1, 1, 1); 6 | } -------------------------------------------------------------------------------- /Chapter17/shaders/vertexcolvert.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec3 position; 3 | uniform mat4 projection_mat; 4 | uniform mat4 view_mat; 5 | uniform mat4 model_mat; 6 | void main() 7 | { 8 | gl_Position = projection_mat * transpose(view_mat) * transpose(model_mat) * vec4(position, 1); 9 | } -------------------------------------------------------------------------------- /Chapter17/starter/Button.py: -------------------------------------------------------------------------------- 1 | # import math 2 | import pygame.mouse 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from pygame.locals import * 6 | from Settings import * 7 | 8 | class Button: 9 | def __init__(self, screen, position, width, height, color, o_color, p_color, on_click): 10 | self.screen = screen 11 | self.position = position 12 | self.width = width 13 | self.height = height 14 | self.normal_color = color 15 | self.over_color = o_color 16 | self.pressed_color = p_color 17 | self.on_click = on_click 18 | self.mouse_down = False 19 | 20 | 21 | def draw(self, events): 22 | mouse_pos = pygame.mouse.get_pos() 23 | mx = map_value(window_dimensions[0], window_dimensions[1], 24 | gui_dimensions[0], gui_dimensions[1], 25 | mouse_pos[0]) 26 | my = map_value(window_dimensions[2], window_dimensions[3], 27 | gui_dimensions[2], gui_dimensions[3], 28 | mouse_pos[1]) 29 | 30 | glPushMatrix() 31 | glLoadIdentity() 32 | # If the mouse is over the button 33 | if self.position[0] < mx < (self.position[0] + self.width) and self.position[1] < my < (self.position[1] + self.height): 34 | for e in events: 35 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 36 | self.mouse_down = True 37 | self.on_click() 38 | elif e.type == MOUSEBUTTONUP and e.button == 1: 39 | self.mouse_down = False 40 | if self.mouse_down: 41 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 42 | else: 43 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]) 44 | else: 45 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]) 46 | glBegin(GL_POLYGON) 47 | glVertex2f(self.position[0], self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1]) 49 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 50 | glVertex2f(self.position[0], self.position[1] + self.height) 51 | glEnd() 52 | glPopMatrix() -------------------------------------------------------------------------------- /Chapter17/starter/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | -------------------------------------------------------------------------------- /Chapter17/starter/Cube.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | 3 | class Cube(Mesh3D): 4 | def __init__(self, draw_type, filename): 5 | self.vertices = [(0.5, -0.5, 0.5), 6 | (-0.5, -0.5, 0.5), 7 | (0.5, 0.5, 0.5), 8 | (-0.5, 0.5, 0.5), 9 | (0.5, 0.5, -0.5), 10 | (-0.5, 0.5, -0.5), 11 | (0.5, -0.5, -0.5), 12 | (-0.5, -0.5, -0.5), 13 | (0.5, 0.5, 0.5), 14 | (-0.5, 0.5, 0.5), 15 | (0.5, 0.5, -0.5), 16 | (-0.5, 0.5, -0.5), 17 | (0.5, -0.5, -0.5), 18 | (0.5, -0.5, 0.5), 19 | (-0.5, -0.5, 0.5), 20 | (-0.5, -0.5, -0.5), 21 | (-0.5, -0.5, 0.5), 22 | (-0.5, 0.5, 0.5), 23 | (-0.5, 0.5, -0.5), 24 | (-0.5, -0.5, -0.5), 25 | (0.5, -0.5, -0.5), 26 | (0.5, 0.5, -0.5), 27 | (0.5, 0.5, 0.5), 28 | (0.5, -0.5, 0.5)] 29 | 30 | self.triangles = [0, 2, 3, 0, 3, 1, 8, 4, 5, 31 | 8, 5, 9, 10, 6, 7, 10, 7, 11, 32 | 12, 13, 14, 12, 14, 15, 16, 17, 18, 33 | 16, 18, 19, 20, 21, 22, 20, 22, 23] 34 | 35 | self.uvs = [(0.0, 0.0), 36 | (1.0, 0.0), 37 | (0.0, 1.0), 38 | (1.0, 1.0), 39 | (0.0, 1.0), 40 | (1.0, 1.0), 41 | (0.0, 1.0), 42 | (1.0, 1.0), 43 | (0.0, 0.0), 44 | (1.0, 0.0), 45 | (0.0, 0.0), 46 | (1.0, 0.0), 47 | (0.0, 0.0), 48 | (0.0, 1.0), 49 | (1.0, 1.0), 50 | (1.0, 0.0), 51 | (0.0, 0.0), 52 | (0.0, 1.0), 53 | (1.0, 1.0), 54 | (1.0, 0.0), 55 | (0.0, 0.0), 56 | (0.0, 1.0), 57 | (1.0, 1.0), 58 | (1.0, 0.0)] 59 | 60 | Mesh3D.draw_type = draw_type 61 | Mesh3D.texture = pygame.image.load(filename) 62 | Mesh3D.int_texture(self) -------------------------------------------------------------------------------- /Chapter17/starter/Display_Normals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | norm = cross_product(p, q) 23 | 24 | # find median 25 | midpoint = vertex3 + q * 0.5 26 | v = (midpoint - vertex1) * 2 / 3 27 | centroid = vertex1 + v 28 | self.normals.append((centroid, centroid + norm * 10)) 29 | 30 | def draw(self): 31 | glColor3fv((0, 1, 0)) 32 | glBegin(GL_LINES) 33 | for i in range(0, len(self.normals)): 34 | start_point = self.normals[i][0] 35 | end_point = self.normals[i][1] 36 | glVertex3fv((start_point[0], start_point[1], 37 | start_point[2])) 38 | glVertex3fv((end_point[0], end_point[1], 39 | end_point[2])) 40 | glEnd() 41 | -------------------------------------------------------------------------------- /Chapter17/starter/GraphicsData.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | class GraphicsData(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.buffer_ref = glGenBuffers(1) 9 | self.load() 10 | 11 | def load(self): 12 | data = np.array(self.data, np.float32) 13 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 14 | glBufferData(GL_ARRAY_BUFFER, data.ravel(), GL_STATIC_DRAW) 15 | 16 | def create_variable(self, program_id, variable_name): 17 | variable_id = glGetAttribLocation(program_id, variable_name) 18 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 19 | if self.data_type == "vec3": 20 | glVertexAttribPointer(variable_id, 3, GL_FLOAT, False, 0, None) 21 | elif self.data_type == "vec2": 22 | glVertexAttribPointer(variable_id, 2, GL_FLOAT, False, 0, None) 23 | 24 | glEnableVertexAttribArray(variable_id) 25 | -------------------------------------------------------------------------------- /Chapter17/starter/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | class Grid(): 4 | def __init__(self, interval, halfsize, color): 5 | self.interval = interval 6 | self.halfsize = halfsize 7 | self.color = color 8 | 9 | def draw(self): 10 | glColor3fv(self.color) 11 | glBegin(GL_LINES) 12 | for x in range(-self.halfsize, self.halfsize): 13 | for y in range(-self.halfsize, self.halfsize): 14 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 15 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 16 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 17 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 18 | glEnd() 19 | -------------------------------------------------------------------------------- /Chapter17/starter/Material.py: -------------------------------------------------------------------------------- 1 | from Utils import * 2 | 3 | class Material: 4 | def __init__(self, vertex_shader, fragment_shader): 5 | self.program_id = create_program(open(vertex_shader).read(), open(fragment_shader).read()) 6 | 7 | def use(self): 8 | glUseProgram(self.program_id) 9 | -------------------------------------------------------------------------------- /Chapter17/starter/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), 5 | (v.x*w.z - v.z*w.x), 6 | (v.x*w.y - v.y*w.x)) 7 | -------------------------------------------------------------------------------- /Chapter17/starter/Mesh3D.py: -------------------------------------------------------------------------------- 1 | import pygame.image 2 | from OpenGL.GL import * 3 | 4 | class Mesh3D: 5 | def __init__(self): 6 | self.vertices = [(0.5, -0.5, 0.5), 7 | (-0.5, -0.5, 0.5), 8 | (0.5, 0.5, 0.5), 9 | (-0.5, 0.5, 0.5), 10 | (0.5, 0.5, -0.5), 11 | (-0.5, 0.5, -0.5)] 12 | 13 | self.triangles = [0, 2, 3, 0, 3, 1] 14 | self.draw_type = GL_LINE_LOOP 15 | self.texture = pygame.image.load() 16 | self.texID = 0 17 | 18 | def draw(self): 19 | glEnable(GL_TEXTURE_2D) 20 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 21 | glBindTexture(GL_TEXTURE_2D, self.texID) 22 | for t in range(0, len(self.triangles), 3): 23 | glBegin(self.draw_type) 24 | glTexCoord2fv(self.uvs[self.triangles[t]]) 25 | glVertex3fv(self.vertices[self.triangles[t]]) 26 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 27 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 28 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 29 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 30 | glEnd() 31 | glDisable(GL_TEXTURE_2D) 32 | 33 | def int_texture(self): 34 | self.texID = glGenTextures(1) 35 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 36 | width = self.texture.get_width() 37 | height = self.texture.get_height() 38 | glBindTexture(GL_TEXTURE_2D, self.texID) 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 40 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) -------------------------------------------------------------------------------- /Chapter17/starter/Object.py: -------------------------------------------------------------------------------- 1 | from Mesh3D import * 2 | from Transform import * 3 | from Button import * 4 | from Grid import * 5 | from Display_Normals import * 6 | from Camera import * 7 | 8 | class Object: 9 | def __init__(self, obj_name): 10 | self.name = obj_name 11 | self.components = [] 12 | self.scene_angle = 0 13 | 14 | def add_component(self, component): 15 | if isinstance(component, Transform): 16 | self.components.insert(0, self.components) 17 | self.components.append(component) 18 | 19 | def update(self, camera: Camera, events = None): 20 | glPushMatrix() 21 | for c in self.components: 22 | if isinstance(c, Transform): 23 | glLoadMatrixf(c.get_MVM() * camera.get_VM()) 24 | #mv = glGetDoublev(GL_MODELVIEW_MATRIX) 25 | #print("MV: ") 26 | #print(mv) 27 | elif isinstance(c, Mesh3D): 28 | glColor(1, 1, 1) 29 | c.draw() 30 | elif isinstance(c, Grid): 31 | c.draw() 32 | elif isinstance(c,DisplayNormals): 33 | c.draw() 34 | 35 | glPopMatrix() 36 | 37 | def get_component(self, class_type): 38 | for c in self.components: 39 | if type(c) is class_type: 40 | return c 41 | return None 42 | -------------------------------------------------------------------------------- /Chapter17/starter/Quaternion.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import pygame 3 | import math 4 | import numpy as np 5 | import sys 6 | 7 | class Quaternion: 8 | def __init__(self, vector=None, axis: pygame.Vector3 = None, angle: float=None): 9 | if vector is not None: 10 | self.w = vector[0] 11 | self.x = vector[1] 12 | self.y = vector[2] 13 | self.z = vector[3] 14 | else: 15 | axis = axis.normalize() 16 | sin_angle = math.sin(math.radians(angle/2.0)) 17 | cos_angle = math.cos(math.radians(angle/2.0)) 18 | self.w = cos_angle 19 | self.x = axis.x * sin_angle 20 | self.y = axis.y * sin_angle 21 | self.z = axis.z * sin_angle 22 | self.normalise() 23 | 24 | def normalise(self): 25 | l = math.sqrt(self.w * self.w + self.x * self.x + 26 | self.y * self.y + self.z * self.z) 27 | if l > sys.float_info.epsilon: 28 | self.w /= l 29 | self.x /= l 30 | self.y /= l 31 | self.z /= l 32 | 33 | def __mul__(self, other: Quaternion): 34 | v1 = pygame.Vector3(self.x, self.y, self.z) 35 | v2 = pygame.Vector3(other.x, other.y, other.z) 36 | cross = v1.cross(v2) 37 | dot = v1.dot(v2) 38 | v3 = cross + (self.w * v2) + (other.w * v1) 39 | result = Quaternion(vector=(self.w * other.w - dot, v3.x, v3.y, v3.z)) 40 | return result 41 | 42 | def get_matrix(self): 43 | x2 = self.x + self.x 44 | y2 = self.y + self.y 45 | z2 = self.z + self.z 46 | xx2 = self.x * x2 47 | xy2 = self.x * y2 48 | xz2 = self.x * z2 49 | yy2 = self.y * y2 50 | yz2 = self.y * z2 51 | zz2 = self.z * z2 52 | wx2 = self.w * x2 53 | wy2 = self.w * y2 54 | wz2 = self.w * z2 55 | 56 | return np.matrix([ 57 | [1 - (yy2 + zz2), xy2 + wz2, xz2 - wy2, 0], 58 | [ xy2 - wz2, 1 - (xx2 + zz2), yz2 + wx2, 0], 59 | [xz2 + wy2, yz2 - wx2, 1 - (xx2 + yy2), 0], 60 | [0, 0, 0, 1]]) 61 | 62 | -------------------------------------------------------------------------------- /Chapter17/starter/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | -------------------------------------------------------------------------------- /Chapter17/starter/ShaderTeapot.py: -------------------------------------------------------------------------------- 1 | from Object import * 2 | from pygame.locals import * 3 | from Camera import * 4 | from LoadMesh import * 5 | from Material import * 6 | from Settings import * 7 | 8 | pygame.init() 9 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1) 10 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES, 4) 11 | pygame.display.gl_set_attribute(pygame.GL_CONTEXT_PROFILE_MASK, pygame.GL_CONTEXT_PROFILE_CORE) 12 | # Only use on Mac as on PC it will throw errors 13 | #pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 32) 14 | 15 | screen_width = math.fabs(window_dimensions[1] - window_dimensions[0]) 16 | screen_height = math.fabs(window_dimensions[3] - window_dimensions[2]) 17 | pygame.display.set_caption('OpenGL in Python') 18 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 19 | done = False 20 | white = pygame.Color(255, 255, 255) 21 | glDisable(GL_CULL_FACE) 22 | glEnable(GL_DEPTH_TEST) 23 | glEnable(GL_BLEND) 24 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 25 | objects_3d = [] 26 | camera = Camera(60, (screen_width / screen_height), 0.01, 10000.0) 27 | 28 | quat_teapot = Object("Teapot") 29 | quat_teapot.add_component(Transform()) 30 | mat = Material("shaders/vertexcolvert.vs", "shaders/vertexcolfrag.vs") 31 | quat_teapot.add_component(LoadMesh(quat_teapot.vao_ref, mat, GL_LINE_LOOP, "models/teapotSM.obj")) 32 | quat_teapot.add_component(mat) 33 | quat_trans: Transform = quat_teapot.get_component(Transform) 34 | quat_trans.update_position(pygame.Vector3(3, 0, -10)) 35 | 36 | objects_3d.append(quat_teapot) 37 | 38 | clock = pygame.time.Clock() 39 | fps = 30 40 | 41 | pygame.event.set_grab(True) 42 | pygame.mouse.set_visible(False) 43 | while not done: 44 | events = pygame.event.get() 45 | for event in events: 46 | if event.type == pygame.QUIT: 47 | done = True 48 | if event.type == KEYDOWN: 49 | if event.key == K_ESCAPE: 50 | pygame.mouse.set_visible(True) 51 | pygame.event.set_grab(False) 52 | if event.key == K_SPACE: 53 | pygame.mouse.set_visible(False) 54 | pygame.event.set_grab(True) 55 | 56 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 57 | camera.update() 58 | for o in objects_3d: 59 | o.update(camera, events) 60 | 61 | pygame.display.flip() 62 | dt = clock.tick(fps) 63 | pygame.quit() 64 | 65 | -------------------------------------------------------------------------------- /Chapter17/starter/Uniform.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Uniform(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.variable_id = None 9 | 10 | def find_variable(self, program_id, variable_name): 11 | self.variable_id = glGetUniformLocation(program_id, variable_name) 12 | 13 | def load(self): 14 | if self.data_type == "vec3": 15 | glUniform3f(self.variable_id, self.data[0], self.data[1], self.data[2]) 16 | elif self.data_type == "mat4": 17 | glUniformMatrix4fv(self.variable_id, 1, GL_TRUE, 18 | self.data) 19 | elif self.data_type == "sampler2D": 20 | texture_obj, texture_unit = self.data 21 | glActiveTexture(GL_TEXTURE0 + texture_unit) 22 | glBindTexture(GL_TEXTURE_2D, texture_obj) 23 | glUniform1i(self.variable_id, texture_unit) 24 | -------------------------------------------------------------------------------- /Chapter17/starter/Utils.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | def map_value(current_min, current_max, new_min, new_max, value): 5 | current_range = current_max - current_min 6 | new_range = new_max - new_min 7 | return new_min + new_range * ((value - current_min) / current_range) 8 | 9 | def compile_shader(shader_type, shader_source): 10 | shader_id = glCreateShader(shader_type) 11 | glShaderSource(shader_id, shader_source) 12 | glCompileShader(shader_id) 13 | compile_success = glGetShaderiv(shader_id, GL_COMPILE_STATUS) 14 | if not compile_success: 15 | error_message = glGetShaderInfoLog(shader_id) 16 | glDeleteShader(shader_id) 17 | error_message = "\n" + error_message.decode("utf-8") 18 | raise Exception(error_message) 19 | return shader_id 20 | 21 | def create_program(vertex_shader_code, fragment_shader_code): 22 | vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader_code) 23 | fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_code) 24 | program_id = glCreateProgram() 25 | glAttachShader(program_id, vertex_shader_id) 26 | glAttachShader(program_id, fragment_shader_id) 27 | glLinkProgram(program_id) 28 | link_success = glGetProgramiv(program_id, GL_LINK_STATUS) 29 | if not link_success: 30 | info = glGetProgramInfoLog(program_id) 31 | raise RuntimeError(info) 32 | glDeleteShader(vertex_shader_id) 33 | glDeleteShader(fragment_shader_id) 34 | return program_id 35 | -------------------------------------------------------------------------------- /Chapter18/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter18/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter18/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter18/Granny/granny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Mathematics-for-Game-Programming-and-Computer-Graphics/5f7f3d3786decc6d8f877862da9ccf2062bdb4d1/Chapter18/Granny/granny.png -------------------------------------------------------------------------------- /Chapter18/GraphicsData.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | class GraphicsData(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.buffer_ref = glGenBuffers(1) 9 | self.load() 10 | 11 | def load(self): 12 | data = np.array(self.data, np.float32) 13 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 14 | glBufferData(GL_ARRAY_BUFFER, data.ravel(), GL_STATIC_DRAW) 15 | 16 | def create_variable(self, program_id, variable_name): 17 | variable_id = glGetAttribLocation(program_id, variable_name) 18 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 19 | if self.data_type == "vec3": 20 | glVertexAttribPointer(variable_id, 3, GL_FLOAT, False, 0, None) 21 | elif self.data_type == "vec2": 22 | glVertexAttribPointer(variable_id, 2, GL_FLOAT, False, 0, None) 23 | 24 | glEnableVertexAttribArray(variable_id) -------------------------------------------------------------------------------- /Chapter18/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter18/Material.py: -------------------------------------------------------------------------------- 1 | from Utils import * 2 | 3 | class Material: 4 | def __init__(self, vertex_shader, fragment_shader): 5 | self.program_id = create_program(open(vertex_shader).read(), open(fragment_shader).read()) 6 | 7 | def use(self): 8 | glUseProgram(self.program_id) 9 | 10 | -------------------------------------------------------------------------------- /Chapter18/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter18/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter18/Object.py: -------------------------------------------------------------------------------- 1 | from LoadMesh import * 2 | from Camera import * 3 | from Material import * 4 | from Uniform import * 5 | 6 | 7 | class Object: 8 | def __init__(self, obj_name): 9 | self.name = obj_name 10 | self.components = [] 11 | self.material = None 12 | self.vao_ref = glGenVertexArrays(1) 13 | glBindVertexArray(self.vao_ref) 14 | 15 | def add_component(self, component): 16 | if isinstance(component, Transform): 17 | self.components.insert(0, self.components) 18 | if isinstance(component, Material): 19 | self.material = component 20 | self.components.append(component) 21 | 22 | def get_component(self, class_type): 23 | for c in self.components: 24 | if type(c) is class_type: 25 | return c 26 | return None 27 | 28 | 29 | def update(self, camera: Camera, events = None): 30 | self.material.use() 31 | for c in self.components: 32 | if isinstance(c, Transform): 33 | projection = Uniform("mat4", camera.get_PPM()) 34 | projection.find_variable(self.material.program_id, "projection_mat") 35 | projection.load() 36 | 37 | lookat = Uniform("mat4", camera.get_VM()) 38 | lookat.find_variable(self.material.program_id, "view_mat") 39 | lookat.load() 40 | 41 | transformation = Uniform("mat4", c.get_MVM()) 42 | transformation.find_variable(self.material.program_id, "model_mat") 43 | transformation.load() 44 | 45 | elif isinstance(c, LoadMesh): 46 | c.draw() 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Chapter18/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter18/ShaderTeapot.py: -------------------------------------------------------------------------------- 1 | from Object import * 2 | from pygame.locals import * 3 | from Camera import * 4 | from LoadMesh import * 5 | from Material import * 6 | from Settings import * 7 | 8 | pygame.init() 9 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1) 10 | pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES, 4) 11 | pygame.display.gl_set_attribute(pygame.GL_CONTEXT_PROFILE_MASK, pygame.GL_CONTEXT_PROFILE_CORE) 12 | pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 32) 13 | screen_width = math.fabs(window_dimensions[1] - window_dimensions[0]) 14 | screen_height = math.fabs(window_dimensions[3] - window_dimensions[2]) 15 | pygame.display.set_caption('OpenGL in Python') 16 | screen = pygame.display.set_mode((screen_width, screen_height), DOUBLEBUF | OPENGL) 17 | done = False 18 | white = pygame.Color(255, 255, 255) 19 | glDisable(GL_CULL_FACE) 20 | glEnable(GL_DEPTH_TEST) 21 | glEnable(GL_BLEND) 22 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 23 | objects_3d = [] 24 | camera = Camera(60, (screen_width / screen_height), 0.01, 10000.0) 25 | 26 | quat_teapot = Object("Teapot") 27 | quat_teapot.add_component(Transform()) 28 | mat = Material("shaders/texturedvert.vs", "shaders/lambert.vs") 29 | quat_teapot.add_component(LoadMesh(quat_teapot.vao_ref, mat, GL_TRIANGLES, "../models/granny.obj", "../images/granny.png")) 30 | quat_teapot.add_component(mat) 31 | quat_trans: Transform = quat_teapot.get_component(Transform) 32 | quat_trans.update_position(pygame.Vector3(0, -100, -200)) 33 | 34 | objects_3d.append(quat_teapot) 35 | 36 | clock = pygame.time.Clock() 37 | fps = 30 38 | 39 | pygame.event.set_grab(True) 40 | pygame.mouse.set_visible(False) 41 | while not done: 42 | events = pygame.event.get() 43 | for event in events: 44 | if event.type == pygame.QUIT: 45 | done = True 46 | if event.type == KEYDOWN: 47 | if event.key == K_ESCAPE: 48 | pygame.mouse.set_visible(True) 49 | pygame.event.set_grab(False) 50 | if event.key == K_SPACE: 51 | pygame.mouse.set_visible(False) 52 | pygame.event.set_grab(True) 53 | 54 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 55 | camera.update() 56 | for o in objects_3d: 57 | o.update(camera, events) 58 | 59 | pygame.display.flip() 60 | dt = clock.tick(fps) 61 | pygame.quit() 62 | -------------------------------------------------------------------------------- /Chapter18/Texture.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | 4 | class Texture(): 5 | def __init__(self, filename=None): 6 | self.surface = None 7 | self.texture_id = glGenTextures(1) 8 | if filename is not None: 9 | self.surface = pygame.image.load(filename) 10 | self.load() 11 | 12 | def load(self): 13 | width = self.surface.get_width() 14 | height = self.surface.get_height() 15 | 16 | pixel_data = pygame.image.tostring(self.surface, "RGBA", 1) 17 | glBindTexture(GL_TEXTURE_2D, self.texture_id) 18 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data) 19 | glGenerateMipmap(GL_TEXTURE_2D) 20 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) 21 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) 22 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) 23 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) 24 | 25 | -------------------------------------------------------------------------------- /Chapter18/Uniform.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Uniform(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.variable_id = None 9 | 10 | def find_variable(self, program_id, variable_name): 11 | self.variable_id = glGetUniformLocation(program_id, variable_name) 12 | 13 | def load(self): 14 | if self.data_type == "vec3": 15 | glUniform3f(self.variable_id, self.data[0], self.data[1], self.data[2]) 16 | elif self.data_type == "mat4": 17 | glUniformMatrix4fv(self.variable_id, 1, GL_TRUE, self.data) 18 | elif self.data_type == "sampler2D": 19 | texture_obj, texture_unit = self.data 20 | glActiveTexture(GL_TEXTURE0 + texture_unit) 21 | glBindTexture(GL_TEXTURE_2D, texture_obj) 22 | glUniform1i(self.variable_id, texture_unit) -------------------------------------------------------------------------------- /Chapter18/Utils.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | def map_value(current_min, current_max, new_min, new_max, value): 5 | current_range = current_max - current_min 6 | new_range = new_max - new_min 7 | return new_min + new_range * ((value-current_min)/current_range) 8 | 9 | def compile_shader(shader_type, shader_source): 10 | shader_id = glCreateShader(shader_type) 11 | glShaderSource(shader_id, shader_source) 12 | glCompileShader(shader_id) 13 | compile_success = glGetShaderiv(shader_id, GL_COMPILE_STATUS) 14 | if not compile_success: 15 | error_message = glGetShaderInfoLog(shader_id) 16 | glDeleteShader(shader_id) 17 | error_message = "\n" + error_message.decode("utf-8") 18 | raise Exception(error_message) 19 | return shader_id 20 | 21 | def create_program(vertex_shader_code, fragment_shader_code): 22 | vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader_code) 23 | fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_code) 24 | program_id = glCreateProgram() 25 | glAttachShader(program_id, vertex_shader_id) 26 | glAttachShader(program_id, fragment_shader_id) 27 | glLinkProgram(program_id) 28 | link_success = glGetProgramiv(program_id, GL_LINK_STATUS) 29 | if not link_success: 30 | info = glGetProgramInfoLog(program_id) 31 | raise RuntimeError(info) 32 | glDeleteShader(vertex_shader_id) 33 | glDeleteShader(fragment_shader_id) 34 | return program_id 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Chapter19/Button.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from OpenGL.GL import * 4 | from Utils import * 5 | from Settings import * 6 | 7 | class Button: 8 | def __init__(self, screen, position, width, height, color, ocolor, pcolor, on_click): 9 | self.position = position 10 | self.width = width 11 | self.height = height 12 | self.screen = screen 13 | self.normal_color = color 14 | self.over_color = ocolor 15 | self.pressed_color = pcolor 16 | self.mouse_down = False 17 | self.on_click = on_click 18 | 19 | 20 | def draw(self, events): 21 | mouse_pos = pygame.mouse.get_pos() 22 | mx = map_value(window_dimensions[0], window_dimensions[1], 23 | gui_dimensions[0], gui_dimensions[1], mouse_pos[0]) 24 | my = map_value(window_dimensions[2], window_dimensions[3], 25 | gui_dimensions[2], gui_dimensions[3], mouse_pos[1]) 26 | 27 | glPushMatrix() 28 | glLoadIdentity() 29 | # if mouse over button 30 | if self.position[0] < mx < (self.position[0] + self.width) and \ 31 | self.position[1] < my < (self.position[1] + self.height): 32 | 33 | for e in events: 34 | if e.type == MOUSEBUTTONDOWN and e.button == 1: 35 | self.mouse_down = True 36 | self.on_click() 37 | elif e.type == MOUSEBUTTONUP and e.button == 1: 38 | self.mouse_down = False 39 | if self.mouse_down: 40 | glColor3f(self.pressed_color[0], self.pressed_color[1], self.pressed_color[2]) 41 | else: 42 | glColor3f(self.over_color[0], self.over_color[1], self.over_color[2]); 43 | else: 44 | glColor3f(self.normal_color[0], self.normal_color[1], self.normal_color[2]); 45 | glBegin(GL_POLYGON) 46 | glVertex2f(self.position[0], self.position[1]) 47 | glVertex2f(self.position[0] + self.width, self.position[1]) 48 | glVertex2f(self.position[0] + self.width, self.position[1] + self.height) 49 | glVertex2f(self.position[0], self.position[1] + self.height) 50 | glEnd() 51 | glPopMatrix() 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter19/Camera2D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Camera2D: 5 | def __init__(self, left, right, top, bottom): 6 | near_val = -1 7 | far_val = 1 8 | a = 2/(right-left) 9 | b = 2/(top-bottom) 10 | c = -2/(far_val - near_val) 11 | d = -(right + left)/(right - left) 12 | e = -(top + bottom)/(top - bottom) 13 | f = -(far_val + near_val)/(far_val - near_val) 14 | self.PPM = np.matrix([ 15 | [a, 0, 0, 0], 16 | [0, b, 0, 0], 17 | [0, 0, c, 0], 18 | [d, e, f, 0] 19 | ]) 20 | self.VM = np.identity(4) 21 | 22 | def get_PPM(self): 23 | return self.PPM 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter19/DisplayNormals.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | from MathOGL import * 4 | 5 | 6 | class DisplayNormals: 7 | 8 | def __init__(self, vertices, triangles): 9 | self.vertices = vertices 10 | self.triangles = triangles 11 | self.normals = [] 12 | for t in range(0, len(self.triangles), 3): 13 | vertex1 = self.vertices[self.triangles[t]] 14 | vertex2 = self.vertices[self.triangles[t + 1]] 15 | vertex3 = self.vertices[self.triangles[t + 2]] 16 | p = pygame.Vector3(vertex1[0] - vertex2[0], 17 | vertex1[1] - vertex2[1], 18 | vertex1[2] - vertex2[2]) 19 | q = pygame.Vector3(vertex2[0] - vertex3[0], 20 | vertex2[1] - vertex3[1], 21 | vertex2[2] - vertex3[2]) 22 | 23 | norm = cross_product(p, q) 24 | 25 | #find median 26 | middle = (vertex3 + q * 0.5) 27 | v = (middle - vertex1) * 2/3 28 | median = vertex1 + v 29 | nstart = median 30 | self.normals.append((nstart, nstart + norm * 10)) 31 | print(vertex1, vertex2, vertex3, middle, v, nstart, p, q) 32 | 33 | 34 | def draw(self): 35 | glColor3fv((0, 1, 0)) 36 | glBegin(GL_LINES) 37 | for i in range(0, len(self.normals)): 38 | start_point = self.normals[i][0] 39 | end_point = self.normals[i][1] 40 | glVertex3fv((start_point[0], start_point[1], start_point[2])) 41 | glVertex3fv((end_point[0], end_point[1], end_point[2])) 42 | glEnd() 43 | -------------------------------------------------------------------------------- /Chapter19/GraphicsData.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | class GraphicsData(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.buffer_ref = glGenBuffers(1) 9 | self.load() 10 | 11 | def load(self): 12 | data = np.array(self.data, np.float32) 13 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 14 | glBufferData(GL_ARRAY_BUFFER, data.ravel(), GL_STATIC_DRAW) 15 | 16 | def create_variable(self, program_id, variable_name): 17 | variable_id = glGetAttribLocation(program_id, variable_name) 18 | glBindBuffer(GL_ARRAY_BUFFER, self.buffer_ref) 19 | if self.data_type == "vec3": 20 | glVertexAttribPointer(variable_id, 3, GL_FLOAT, False, 0, None) 21 | elif self.data_type == "vec2": 22 | glVertexAttribPointer(variable_id, 2, GL_FLOAT, False, 0, None) 23 | 24 | glEnableVertexAttribArray(variable_id) -------------------------------------------------------------------------------- /Chapter19/Grid.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Grid(): 5 | def __init__(self, interval, halfsize, colour): 6 | self.interval = interval 7 | self.halfsize = halfsize 8 | self.colour = colour 9 | 10 | def draw(self): 11 | glColor3fv(self.colour) 12 | glBegin(GL_LINES) 13 | for x in range(-self.halfsize, self.halfsize): 14 | for y in range(-self.halfsize, self.halfsize): 15 | glVertex3fv((x * self.interval, y * self.interval - 10, 0)) 16 | glVertex3fv((x * self.interval, y * self.interval + 500, 0)) 17 | glVertex3fv((y * self.interval - 10, x * self.interval, 0)) 18 | glVertex3fv((y * self.interval + 500, x * self.interval, 0)) 19 | glEnd() 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chapter19/Light.py: -------------------------------------------------------------------------------- 1 | from Transform import * 2 | from Uniform import * 3 | 4 | 5 | class Light: 6 | def __init__(self, position=pygame.Vector3(0, 0, 0), color=pygame.Vector3(1, 1, 1), atten=0, light_number=0): 7 | self.position = position 8 | self.atten = atten 9 | self.color = color 10 | self.light_variable = "light_data[" + str(light_number) + "].position" 11 | self.atten_variable = "light_data[" + str(light_number) + "].attenuation" 12 | self.color_variable = "light_data[" + str(light_number) + "].color" 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter19/Material.py: -------------------------------------------------------------------------------- 1 | from Utils import * 2 | 3 | class Material: 4 | def __init__(self, vertex_shader, fragment_shader): 5 | self.program_id = create_program(open(vertex_shader).read(), open(fragment_shader).read()) 6 | 7 | def use(self): 8 | glUseProgram(self.program_id) 9 | 10 | -------------------------------------------------------------------------------- /Chapter19/MathOGL.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | def cross_product(v, w): 4 | return pygame.Vector3((v.y*w.z - v.z*w.y), (v.x*w.z - v.z*w.x), (v.x*w.y - v.y*w.x)) 5 | 6 | -------------------------------------------------------------------------------- /Chapter19/Mesh3D.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import pygame 3 | 4 | 5 | class Mesh3D: 6 | def __init__(self): 7 | self.vertices = [(0.5, -0.5, 0.5), 8 | (-0.5, -0.5, 0.5), 9 | (0.5, 0.5, 0.5), 10 | (-0.5, 0.5, 0.5), 11 | (0.5, 0.5, -0.5), 12 | (-0.5, 0.5, -0.5) 13 | ] 14 | self.triangles = [0, 2, 3, 0, 3, 1] 15 | self.draw_type = GL_LINE_LOOP 16 | self.texture = pygame.image.load() 17 | self.texID = 0 18 | 19 | def init_texture(self): 20 | self.texID = glGenTextures(1) 21 | textureData = pygame.image.tostring(self.texture, "RGB", 1) 22 | width = self.texture.get_width() 23 | height = self.texture.get_height() 24 | glBindTexture(GL_TEXTURE_2D, self.texID) 25 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 26 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData) 27 | 28 | def draw(self): 29 | glEnable(GL_TEXTURE_2D) 30 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 31 | glBindTexture(GL_TEXTURE_2D, self.texID) 32 | for t in range(0, len(self.triangles), 3): 33 | glBegin(self.draw_type) 34 | glTexCoord2fv(self.uvs[self.triangles[t]]) 35 | glVertex3fv(self.vertices[self.triangles[t]]) 36 | glTexCoord2fv(self.uvs[self.triangles[t + 1]]) 37 | glVertex3fv(self.vertices[self.triangles[t + 1]]) 38 | glTexCoord2fv(self.uvs[self.triangles[t + 2]]) 39 | glVertex3fv(self.vertices[self.triangles[t + 2]]) 40 | glEnd() 41 | glDisable(GL_TEXTURE_2D) 42 | -------------------------------------------------------------------------------- /Chapter19/Object.py: -------------------------------------------------------------------------------- 1 | from LoadMesh import * 2 | from Camera import * 3 | from Material import * 4 | from Uniform import * 5 | from Light import * 6 | 7 | 8 | class Object: 9 | def __init__(self, obj_name): 10 | self.name = obj_name 11 | self.components = [] 12 | self.material = None 13 | self.vao_ref = glGenVertexArrays(1) 14 | glBindVertexArray(self.vao_ref) 15 | 16 | def add_component(self, component): 17 | if isinstance(component, Transform): 18 | self.components.insert(0, self.components) 19 | if isinstance(component, Material): 20 | self.material = component 21 | self.components.append(component) 22 | 23 | def get_component(self, class_type): 24 | for c in self.components: 25 | if type(c) is class_type: 26 | return c 27 | return None 28 | 29 | def update(self, camera: Camera, lights: Light([]), events = None): 30 | self.material.use() 31 | for c in self.components: 32 | if isinstance(c, Transform): 33 | projection = Uniform("mat4", camera.get_PPM()) 34 | projection.find_variable(self.material.program_id, "projection_mat") 35 | projection.load() 36 | 37 | lookat = Uniform("mat4", camera.get_VM()) 38 | lookat.find_variable(self.material.program_id, "view_mat") 39 | lookat.load() 40 | 41 | transformation = Uniform("mat4", c.get_MVM()) 42 | transformation.find_variable(self.material.program_id, "model_mat") 43 | transformation.load() 44 | 45 | for l in lights: 46 | light_pos = Uniform("vec3", l.position) 47 | light_pos.find_variable(self.material.program_id, l.light_variable) 48 | light_pos.load() 49 | light_atten = Uniform("float", l.atten) 50 | light_atten.find_variable(self.material.program_id, l.atten_variable) 51 | light_atten.load() 52 | color = Uniform("vec3", l.color) 53 | color.find_variable(self.material.program_id, l.color_variable) 54 | color.load() 55 | 56 | 57 | 58 | elif isinstance(c, LoadMesh): 59 | c.draw() 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Chapter19/Settings.py: -------------------------------------------------------------------------------- 1 | # the actual size of the window in pixels 2 | # left, right, top, bottom 3 | window_dimensions = (0, 800, 0, 600) 4 | # the resolution of an Ortho2D projection used for drawing the GUI 5 | # left, right, top, bottom 6 | gui_dimensions = (0, 1600, 1200, 0) 7 | 8 | -------------------------------------------------------------------------------- /Chapter19/Texture.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from OpenGL.GL import * 3 | 4 | class Texture(): 5 | def __init__(self, filename=None): 6 | self.surface = None 7 | self.texture_id = glGenTextures(1) 8 | if filename is not None: 9 | self.surface = pygame.image.load(filename) 10 | self.load() 11 | 12 | def load(self): 13 | width = self.surface.get_width() 14 | height = self.surface.get_height() 15 | 16 | pixel_data = pygame.image.tostring(self.surface, "RGBA", 1) 17 | glBindTexture(GL_TEXTURE_2D, self.texture_id) 18 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data) 19 | glGenerateMipmap(GL_TEXTURE_2D) 20 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) 21 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) 22 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) 23 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) 24 | 25 | -------------------------------------------------------------------------------- /Chapter19/Uniform.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | 3 | 4 | class Uniform(): 5 | def __init__(self, data_type, data): 6 | self.data_type = data_type 7 | self.data = data 8 | self.variable_id = None 9 | 10 | def find_variable(self, program_id, variable_name): 11 | self.variable_id = glGetUniformLocation(program_id, variable_name) 12 | 13 | def load(self): 14 | if self.data_type == "vec3": 15 | glUniform3f(self.variable_id, self.data[0], self.data[1], self.data[2]) 16 | elif self.data_type == "float": 17 | glUniform1f(self.variable_id, self.data) 18 | elif self.data_type == "mat4": 19 | glUniformMatrix4fv(self.variable_id, 1, GL_TRUE, self.data) 20 | elif self.data_type == "sampler2D": 21 | texture_obj, texture_unit = self.data 22 | glActiveTexture(GL_TEXTURE0 + texture_unit) 23 | glBindTexture(GL_TEXTURE_2D, texture_obj) 24 | glUniform1i(self.variable_id, texture_unit) -------------------------------------------------------------------------------- /Chapter19/Utils.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | import numpy as np 3 | 4 | def map_value(current_min, current_max, new_min, new_max, value): 5 | current_range = current_max - current_min 6 | new_range = new_max - new_min 7 | return new_min + new_range * ((value-current_min)/current_range) 8 | 9 | def compile_shader(shader_type, shader_source): 10 | shader_id = glCreateShader(shader_type) 11 | glShaderSource(shader_id, shader_source) 12 | glCompileShader(shader_id) 13 | compile_success = glGetShaderiv(shader_id, GL_COMPILE_STATUS) 14 | if not compile_success: 15 | error_message = glGetShaderInfoLog(shader_id) 16 | glDeleteShader(shader_id) 17 | error_message = "\n" + error_message.decode("utf-8") 18 | raise Exception(error_message) 19 | return shader_id 20 | 21 | def create_program(vertex_shader_code, fragment_shader_code): 22 | vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader_code) 23 | fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_code) 24 | program_id = glCreateProgram() 25 | glAttachShader(program_id, vertex_shader_id) 26 | glAttachShader(program_id, fragment_shader_id) 27 | glLinkProgram(program_id) 28 | link_success = glGetProgramiv(program_id, GL_LINK_STATUS) 29 | if not link_success: 30 | info = glGetProgramInfoLog(program_id) 31 | raise RuntimeError(info) 32 | glDeleteShader(vertex_shader_id) 33 | glDeleteShader(fragment_shader_id) 34 | return program_id 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Chapter19/shaders/pbrvert.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec3 position; 3 | in vec3 vertex_normal; 4 | //in vec2 vertex_uv; 5 | uniform mat4 projection_mat; 6 | uniform mat4 model_mat; 7 | uniform mat4 view_mat; 8 | out vec3 normal; 9 | out vec2 UV; 10 | out vec3 world_pos; 11 | out vec3 cam_pos; 12 | 13 | void main() 14 | { 15 | gl_Position = projection_mat * transpose(view_mat) * transpose(model_mat) * vec4(position, 1); 16 | //UV = vertex_uv; 17 | normal = mat3(transpose(model_mat)) * vertex_normal; 18 | world_pos = (transpose(model_mat) * vec4(position, 1)).rgb; 19 | cam_pos = vec3(inverse(transpose(model_mat)) * 20 | vec4(view_mat[3][0], view_mat[3][1], view_mat[3][2],1)); 21 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | --------------------------------------------------------------------------------