From 19301d58cd623624e778b51b109c0980240b7e4a Mon Sep 17 00:00:00 2001 From: Miguel Angel Date: Sat, 4 Nov 2017 02:01:27 -0400 Subject: [PATCH] Added sprite rendering. --- Textures/bag.png | Bin 0 -> 17731 bytes py_caster.py | 110 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 Textures/bag.png diff --git a/Textures/bag.png b/Textures/bag.png new file mode 100644 index 0000000000000000000000000000000000000000..cbce5d5b9c0ad9d79a34d14fe3b489e0ef578018 GIT binary patch literal 17731 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 TOftmd00000NkvXXu0mjf#La-# literal 0 HcmV?d00001 diff --git a/py_caster.py b/py_caster.py index 5c4bb57..dd2f77a 100755 --- a/py_caster.py +++ b/py_caster.py @@ -43,10 +43,16 @@ class vec(object): def length(self): return math.sqrt(self.dot(self)) + + def lengthSQ(self): + return self.dot(self) def distance(self, p): return p.sub(self).length() + def distanceSQ(self, p): + return p.sub(self).lengthSQ() + class vec3(vec): def __init__(self, x = 0, y = 0, z = 0): self.x = x @@ -123,11 +129,6 @@ class Ray(object): def __str__(self): return "Origin: " + str(self.o) + " :: Direction: " + str(self.d) - -class Ray3d(Ray): - def __init__(self, origin = vec3(0.0, 0.0, 0.0), direction = vec3(0.0, 0.0, 1.0)): - self.o = origin - self.d = direction.normalize() ############################################################## # Intersection Class @@ -137,7 +138,7 @@ class Intersection(object): def __init__(self, r, t, tex_coord = None): self.p = r.o.add(r.d.scale(t)) self.d = r.o.distance(self.p) - self.tc = tex_coord if tex_coord is not None else vec2(self.p.x, self.p.z) + self.tc = tex_coord ############################################################## # Line Segment Class @@ -151,7 +152,7 @@ class LineSegment(object): self.n = vec2(-self.v.y, self.v.x) self.tca = tca self.tcb = tcb - self.texture = pygame.image.load(texture) + self.texture = pygame.image.load(texture).convert() def intersect(self, r): def classifyPoint2D(point): @@ -200,7 +201,7 @@ class LineSegment(object): class Plane3d(object): def __init__(self, texture): - self.texture = pygame.image.load(texture) + self.texture = pygame.image.load(texture).convert() def sample_texture(self, st): w = self.texture.get_width() @@ -210,7 +211,22 @@ class Plane3d(object): t = st.y * h if st.y >= 0.0 else (1.0 - (math.ceil(st.y) - st.y)) * h t = int(t % h) return pygame.Rect(s, t, 1, 1) + +############################################################## +# Sprite class +############################################################## +class Sprite(object): + def __init__(self, position, texture): + self.p = position + self.d = 0.0 + self.texture = pygame.image.load(texture).convert_alpha() + + def sample_texture(self, s): + _s = s % self.texture.get_width() + # Creating a subsurface is pretty fast in pygame, no copying of pixels is needed + return self.texture.subsurface(pygame.Rect(_s, 0, 1, self.texture.get_height())) + ############################################################## # Main Function ############################################################## @@ -244,10 +260,17 @@ def main(): LineSegment(vec2(-3.0, -3.0), vec2(-3.0, 3.0), 0.0, 6.0, "Textures/metal.jpg"), LineSegment(vec2(2.0, 2.0), vec2(3.0, 3.0), 0.0, 1.0, "Textures/diagmetal.jpg"), LineSegment(vec2(-2.0, 2.0), vec2(-3.0, 3.0), 0.0, 1.0, "Textures/diagmetal.jpg"), - LineSegment(vec2(-2.0, 2.0), vec2(2.0, 2.0), 0.0, 4.0, "Textures/diagmetal.jpg") + LineSegment(vec2(-2.0, 2.0), vec2(2.0, 2.0), 0.0, 4.0, "Textures/diagmetal.jpg"), + LineSegment(vec2(-0.5, -1.0), vec2(-0.5, -3.0), 0.0, 1.0, "Textures/orangetiles.jpg"), + LineSegment(vec2(-0.5, -1.0), vec2(0.5, -1.0), 0.0, 1.0, "Textures/orangetiles.jpg"), + LineSegment(vec2(0.5, -1.0), vec2(0.5, -3.0), 0.0, 1.0, "Textures/orangetiles.jpg") ] floor = Plane3d(FLOOR_TEXTURE) ceiln = Plane3d(CEIL_TEXTURE) + sprites = [ + Sprite(vec2(-1.5, -2.0), "Textures/bag.png"), + Sprite(vec2(1.5, -2.0), "Textures/bag.png") + ] # Main game loop. try: @@ -257,6 +280,7 @@ def main(): # Input capture. for event in pygame.event.get(): + # Quit on escape key or window close if (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE) or event.type == pygame.QUIT: done = True @@ -277,6 +301,7 @@ def main(): player_pos = player_pos.sub(player_dir.scale(PLAYER_MOVE_SPEED)) if arrow_keys[pygame.K_LEFT]: + # Apply a rotation matrix to the view and projection vectors oldDirX = player_dir.x; player_dir.x = player_dir.x * math.cos(PLAYER_TURN_SPEED) - player_dir.y * math.sin(PLAYER_TURN_SPEED); player_dir.y = oldDirX * math.sin(PLAYER_TURN_SPEED) + player_dir.y * math.cos(PLAYER_TURN_SPEED); @@ -285,6 +310,7 @@ def main(): plane.y = oldPlaneX * math.sin(PLAYER_TURN_SPEED) + plane.y * math.cos(PLAYER_TURN_SPEED); if arrow_keys[pygame.K_RIGHT]: + # Apply a rotation matrix to the view and projection vectors oldDirX = player_dir.x; player_dir.x = player_dir.x * math.cos(-PLAYER_TURN_SPEED) - player_dir.y * math.sin(-PLAYER_TURN_SPEED); player_dir.y = oldDirX * math.sin(-PLAYER_TURN_SPEED) + player_dir.y * math.cos(-PLAYER_TURN_SPEED); @@ -321,8 +347,10 @@ def main(): if c is not None: # If an intersection was found then compute the projected height of the wall in pixels h = int(float(FB_SIZE[1]) / (d * math.cos(angle * DEG2RAD))) + # The height tends to infinity as we get close to the walls so it must be clamped h = HEIGHT_CLAMP_MULTIPLER * FB_SIZE[1] if h > HEIGHT_CLAMP_MULTIPLER * FB_SIZE[1] else h + # Then scale the corresponding texture slice and blit it scaled = pygame.transform.scale(c, (c.get_width(), h)) frame_buffer.blit(scaled, (i, -(h / 2) + (FB_SIZE[1] / 2))) @@ -361,7 +389,69 @@ def main(): frame_buffer.fill((depth, depth, depth), pygame.Rect(i, FB_SIZE[1] - j, 1, 1), pygame.BLEND_MULT) angle += ANGLE_INCREMENT - + + # Sort the sprites by distance + for s in sprites: + s.d = player_pos.distanceSQ(s.p) + sprites.sort(key = lambda s: s.d, reverse = True) + + # Render the sprites + for s in sprites: + # Take sprite to eye space + sp_eye = s.p.sub(player_pos) + + # Apply inverse camera matrix to sp_eye + inv_det = 1.0 / ((plane.x * player_dir.y) - (player_dir.x * plane.y)) + tx = inv_det * ((player_dir.y * sp_eye.x) - (player_dir.x * sp_eye.y)) + ty = inv_det * ((-plane.y * sp_eye.x) + (plane.x * sp_eye.y)) + + # If the sprite is behind the eye there is no need to continue with this sprite + if ty <= 0.0: + continue + + # Compute sprite x position in image space, width and height + sp_screen_x = int((FB_SIZE[0] / 2) * (1.0 + (tx / ty))) + sh = int(abs(FB_SIZE[1] / ty)) + sw = sh # The sprites are always square + + # Compute draw rows + draw_start_y = int((-sh / 2) + (FB_SIZE[1] / 2)) + draw_start_y = 0 if draw_start_y < 0 else draw_start_y + draw_end_y = int((sh / 2) + (FB_SIZE[1] / 2)) + draw_end_y = FB_SIZE[1] - 1 if draw_end_y >= FB_SIZE[1] else draw_end_y + + # Compute draw cols + draw_start_x = int((-sw / 2) + sp_screen_x) + draw_start_x = 0 if draw_start_x < 0 else draw_start_x + draw_end_x = int((sw / 2) + sp_screen_x) + draw_end_x = FB_SIZE[0] if draw_end_x >= FB_SIZE[0] else draw_end_x + + # Draw columns + tw = s.texture.get_width() + for i in xrange(draw_start_x, draw_end_x): + # Compute tex coord of sprite slice + tc = int((i - (-sw / 2 + sp_screen_x)) * tw / sw) + + # Draw only if the sprite slice is actually inside the screen and there are no walls in front of it + if i >= 0 and i < FB_SIZE[0] and ty < depth_buffer[i]: + # Get texture slice and scale it to it's on-screen height + c = s.sample_texture(tc) + scaled = pygame.transform.scale(c, (c.get_width(), sh)) + + # Darken the texture by distance + _d = (ty if ty < FAR else FAR) / FAR + depth = 255 - int(_d * 255) + scaled.fill((depth, depth, depth, 1.0), + pygame.Rect(0, + 0, + 1, + sh), + pygame.BLEND_MULT + ) + + # Draw the sprite + frame_buffer.blit(scaled, (i, draw_start_y)) + # Render framebuffer to the screen pygame.transform.scale(frame_buffer, SCREEN_SIZE, screen)