OpenGL how to manage negative normals? - c++

With a cube defined as in the following code, you see that normals are often negative in one axis. (even if we calcultate them)
OpenGL manages it with its fixed pipeline, correct me if I'm wrong, but with programmable pipeline, it causes artifacts like black faces. (My previous stackoverflow question provides code.)
I managed to run my code with an operation on my normals (normal = (0.5 + 0.5 * normal); ), but even if the result looks ok, I wonder if my normals are still valid? (And is this operation the best?)
I mean, from a shader point of view, can I still use them to shade or brighten my models? How do you usually do?
The mentionned normals:
const GLfloat cube_vertices[] = {
1, 1, 1, -1, 1, 1, -1,-1, 1, // v0-v1-v2 (front)
-1,-1, 1, 1,-1, 1, 1, 1, 1, // v2-v3-v0
1, 1, 1, 1,-1, 1, 1,-1,-1, // v0-v3-v4 (right)
1,-1,-1, 1, 1,-1, 1, 1, 1, // v4-v5-v0
1, 1, 1, 1, 1,-1, -1, 1,-1, // v0-v5-v6 (top)
-1, 1,-1, -1, 1, 1, 1, 1, 1, // v6-v1-v0
-1, 1, 1, -1, 1,-1, -1,-1,-1, // v1-v6-v7 (left)
-1,-1,-1, -1,-1, 1, -1, 1, 1, // v7-v2-v1
-1,-1,-1, 1,-1,-1, 1,-1, 1, // v7-v4-v3 (bottom)
1,-1, 1, -1,-1, 1, -1,-1,-1, // v3-v2-v7
1,-1,-1, -1,-1,-1, -1, 1,-1, // v4-v7-v6 (back)
-1, 1,-1, 1, 1,-1, 1,-1,-1 }; // v6-v5-v4
const GLfloat cube_normalsI[] = {
0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2 (front)
0, 0, 1, 0, 0, 1, 0, 0, 1, // v2-v3-v0
1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4 (right)
1, 0, 0, 1, 0, 0, 1, 0, 0, // v4-v5-v0
0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6 (top)
0, 1, 0, 0, 1, 0, 0, 1, 0, // v6-v1-v0
-1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7 (left)
-1, 0, 0, -1, 0, 0, -1, 0, 0, // v7-v2-v1
0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3 (bottom)
0,-1, 0, 0,-1, 0, 0,-1, 0, // v3-v2-v7
0, 0,-1, 0, 0,-1, 0, 0,-1, // v4-v7-v6 (back)
0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v6-v5-v4

No, this makes no sense at all. Either you need to update your question or you got it all wrong.
Normal may face any direction and normals are often negative in one axis is completely natural. Why wouldn't they be? From what you are describing you seem to be working with lighting. A part of lighting uses normal to see what is the angle between light source and surface. The idea here is that when you turn the normal a light ray effectively lightens a larger part of surface which reduces density of reflected light. With basic math you can see that the correlation is cos(angle) so parallel vectors will produce highest brightness. Since we are using vectors we are better of replacing cos with dot product.
So at some point you have
float factor = dot(normalize(normal), normalize(lightSource-surfacePoint))
Let's have 2 examples here:
normal = (0, 1, 0)
lightSource = (0, 1, 0)
surfacePoint = (0, 0, 0)
dot((0, 1, 0), (0, 1, 0)) = 0+1+0 = 1
and turn it around:
normal = (-1, 0, 0)
lightSource = (-3, 1, 0)
surfacePoint = (0, 1, 0)
dot((-1, 0, 0), normalize(-3, 0, 0)) = dot((-1, 0, 0), (1, 0, 0)) = 1+0+0 = 1
so even if positions are completely changed and normals negative we will get the same result for same angles (in these cases the vectors being perpendicular).
The only question here is what to do when dot product is negative. That happens when normal faces away from the light. In your case you have a cube and all normals point outwards. What if you needed to be inside a cube and still have lighting? You will get
normal = (0, 1, 0)
lightSource = (0, 0, 0)
surfacePoint = (0, 1, 0)
dot((0, 1, 0), (0, -1, 0)) = 0-1+0 = -1
Because of such cases you need to either clam the values or use absolute values. Clamping will produce interior of cube to be black (not lighted) while absolute value will light those as well:
fragmentColor += lightColor*dotFactor // Do nothing and your light will darken the area
fragmentColor += lightColor*abs(dotFactor) // Use absolute value to lighten even if facing away
fragmentColor += lightColor*max(0.0, dotFactor) // Clamp minimum so there are no negative values.
But none of these have nothing to do with normals facing any direction in absolute coordinate system. It just has to do with relative positions between normal, pixel location and light source.

Related

How do I create multiple levels in pygame?

I can't get my "world_data2" and "world_data3" to draw to the screen. only the "world_data" at index position 0 of the "levels" list draws. Everything else seems to be working. The bats and the doors change in every level, but the tile layout stays exactly the same. Is it possibly something to do with my "reset_level" function? or my world class?
Improved code:
# Importing the pygame library
import pygame
# Initializing pygame
pygame.init()
# Clock and frame rate
clock = pygame.time.Clock()
fps = 60
# Creating the game window
screen_width = 1500
screen_height = 1000
screen = pygame.display.set_mode((screen_width, screen_height))
# Setting game window caption
pygame.display.set_caption('Castle Escape')
# Define game variables
tile_size = 50
game_over = 0
main_menu = True
current_level_index = 0
total_levels = 2
# Loading images
background_img = pygame.image.load('Assets/Images/purplebackground.jpg')
restart_img = pygame.image.load('Assets/Images/Sprites/Buttons/restart.png')
restart_img = pygame.transform.scale(restart_img, (80, 40))
play_img = pygame.image.load('Assets/Images/Sprites/Buttons/play.png')
play_img = pygame.transform.scale(play_img, (350, 190))
exit_img = pygame.image.load('Assets/Images/Sprites/Buttons/exit.png')
exit_img = pygame.transform.scale(exit_img, (350, 190))
controls_img = pygame.image.load('Assets/Images/Sprites/Buttons/controls.png')
controls_img = pygame.transform.scale(controls_img, (350, 190))
settings_img = pygame.image.load('Assets/Images/Sprites/Buttons/settings.png')
settings_img = pygame.transform.scale(settings_img, (350, 190))
menu_img = pygame.image.load('Assets/Images/Sprites/Buttons/menu.png')
menu_img = pygame.transform.scale(menu_img, (80, 40))
# Instances for groups
bat_group = pygame.sprite.Group()
door_group = pygame.sprite.Group()
# Function to draw grid
def draw_grid():
for line in range(0, 30):
pygame.draw.line(screen, (255, 255, 255), (0, line * tile_size), (screen_width, line * tile_size))
pygame.draw.line(screen, (255, 255, 255), (line * tile_size, 0), (line * tile_size, screen_height))
# Function to reset levels
def reset_level(current_level_index):
# Reset player position
player.reset(100, screen_height - 130)
# Empty groups
bat_group.empty()
door_group.empty()
# Load in level data and create world
if current_level_index <= total_levels:
level = levels[current_level_index]
world = World(level)
return world
# Class for world map
class World:
# Constructor
def __init__(self, data):
# List to store locations of tiles
self.tile_list = []
# Load images
ground_img = pygame.image.load('Assets/Medieval Tileset/PNG/Tiles/tile59.png')
ground2_img = pygame.image.load('Assets/Medieval Tileset/PNG/Tiles/tile34.png')
leftwall_img = pygame.image.load('Assets/Medieval Tileset/PNG/Tiles/tile56.png')
rightwall_img = pygame.image.load('Assets/Medieval Tileset/PNG/Tiles/tile58.png')
ceiling_img = pygame.image.load('Assets/Medieval Tileset/PNG/Tiles/tile146.png')
# Loop to run through each row of world grid
row_count = 0
for row in data:
# Loop to run through each column in each row of world grid
col_count = 0
for tile in row:
if tile == 1:
# Scale images to 50 x 50px
img = pygame.transform.scale(ground_img, (tile_size, tile_size))
# Take rectangle
img_rect = img.get_rect()
# x and y coordinates for rectangle
img_rect.x = col_count * tile_size
img_rect.y = row_count * tile_size
tile = (img, img_rect)
self.tile_list.append(tile)
if tile == 2:
# Scale images to 50 x 50px
img = pygame.transform.scale(leftwall_img, (tile_size, tile_size))
# Take rectangle
img_rect = img.get_rect()
# x and y coordinates for rectangle
img_rect.x = col_count * tile_size
img_rect.y = row_count * tile_size
tile = (img, img_rect)
self.tile_list.append(tile)
if tile == 3:
# Scale images to 50 x 50px
img = pygame.transform.scale(rightwall_img, (tile_size, tile_size))
# Take rectangle
img_rect = img.get_rect()
# x and y coordinates for rectangle
img_rect.x = col_count * tile_size
img_rect.y = row_count * tile_size
tile = (img, img_rect)
self.tile_list.append(tile)
if tile == 4:
# Scale images to 50 x 50px
img = pygame.transform.scale(ceiling_img, (tile_size, tile_size))
# Take rectangle
img_rect = img.get_rect()
# x and y coordinates for rectangle
img_rect.x = col_count * tile_size
img_rect.y = row_count * tile_size
tile = (img, img_rect)
self.tile_list.append(tile)
if tile == 5:
# Scale images to 50 x 50px
img = pygame.transform.scale(ground2_img, (tile_size, tile_size))
# Take rectangle
img_rect = img.get_rect()
# x and y coordinates for rectangle
img_rect.x = col_count * tile_size
img_rect.y = row_count * tile_size
tile = (img, img_rect)
self.tile_list.append(tile)
if tile == 6:
# Create instance of bat enemy
bat = Enemy(col_count * tile_size, row_count * tile_size)
bat_group.add(bat)
if tile == 7:
# Create instance of door
door = Doors(col_count * tile_size, row_count * tile_size - 50)
door_group.add(door)
col_count += 1
row_count += 1
# Method to draw tiles to screen
def drawWorld(self):
# Loop to iterate through tile_list
for tile in self.tile_list:
screen.blit(tile[0], tile[1])
pygame.draw.rect(screen, (255, 255, 255), tile[1], 2)
# Class for buttons
class Button:
def __init__(self, x, y, image):
self.image = image
# Create rectangle
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# Check whether mouse click occurs
self.clicked = False
# Draw method
def draw(self):
# Variable holds whether restart button been clicked or not
action = False
# Get mouse position
pos = pygame.mouse.get_pos()
# Check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
# Make sure button can only be clicked once
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
# Draw button
screen.blit(self.image, self.rect)
return action
# Class for player (sprite)
class Player:
# Spawn Player
def __init__(self, x, y):
# Call reset method
self.reset(x, y)
def updatePlayer(self, game_over):
dx = 0 # move along x
dy = 0 # move along y
run_slowDown = 5 # Slow down run animation
if game_over == 0:
# Key controls
key = pygame.key.get_pressed()
# Move player left
if key[pygame.K_LEFT]:
dx -= 3
self.counter += 1
self.direction = -1
# Move player right
if key[pygame.K_RIGHT]:
dx += 3
self.counter += 1
self.direction = 1
# Show idle image if no keys are being pressed
if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False:
self.counter = 0
self.index = 0
if self.direction == 0 or self.direction == 1:
self.image = pygame.image.load('Assets/Images/Sprites/Warrior/Idle/idle1.png')
self.image = pygame.transform.scale(self.image, (60, 90))
if self.direction == -1:
self.image = pygame.image.load('Assets/Images/Sprites/Warrior/Idle/idle1.png')
self.image = pygame.transform.scale(self.image, (60, 90))
self.image = pygame.transform.flip(self.image, True, False)
# Make player jump
self.rect.y += self.vel_y
if key[pygame.K_SPACE] and self.jumped == False and self.in_air == False:
self.vel_y = -12
self.jumped = True
if not key[pygame.K_SPACE]:
self.jumped = False
# Handle animations
if self.counter > run_slowDown:
self.counter = 0
self.index += 1
if self.index >= len(self.transformed_rightRun):
self.index = 0
if self.direction == 1:
self.image = self.transformed_rightRun[self.index]
if self.direction == -1:
self.image = self.images_leftRun[self.index]
# Add gravity
self.vel_y += 1
# Add terminal velocity
if self.vel_y > 2:
self.vel_y = 2
dy += self.vel_y
# Check for collision with tiles
self.in_air = True
for tile in world.tile_list:
# Check for collision in x-direction
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
dx = 0
# Check for collision in y-direction
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
# Check if hitting head on tile (jumping)
if self.vel_y < 0:
dy = tile[1].bottom - self.rect.top
self.vel_y = 0
# Check if landing on tile (falling)
elif self.vel_y >= 0:
dy = tile[1].top - self.rect.bottom
self.vel_y = 0
# Make sure player can only jump once
self.in_air = False
# Check for collision with enemies
if pygame.sprite.spritecollide(self, bat_group, False):
game_over = -1 # Value of -1 triggers game over
# Check collision with doors
if pygame.sprite.spritecollide(self, door_group, False):
game_over = 1 # Value of 1 means player has completed level
# update player coordinates
self.rect.x += dx
self.rect.y += dy
elif game_over == -1:
# Turn player into ghost
self.image = self.dead_image
# Make ghost float up
if self.rect.y > 200:
self.rect.y -= 5
# Draw player to screen
screen.blit(self.image, self.rect)
# Draw rectangle
pygame.draw.rect(screen, (255, 255, 255), self.rect, 2)
return game_over
# Method to reset game
def reset(self, x, y):
# Right run animation list
self.images_rightRun = []
# Append all right run animation images to list
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run1.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run2.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run3.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run4.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run5.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run6.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run7.png'))
self.images_rightRun.append(pygame.image.load('Assets/Images/Sprites/Warrior/Run/run8.png'))
# New transformed right run list
self.transformed_rightRun = []
for img in self.images_rightRun:
self.transformed_rightRun.append(pygame.transform.scale(img, (60, 90)))
# Left run animation list
self.images_leftRun = []
for img in self.transformed_rightRun:
self.images_leftRun.append(pygame.transform.flip(img, True, False))
# Set index and counter of lists to 0
self.index = 0
self.counter = 0 # Counter controls speed of animation
# Load and scale ghost image
self.dead_image = pygame.image.load('Assets/Images/Sprites/Ghost/ghost.png')
self.dead_image = pygame.transform.scale(self.dead_image, (40, 60))
# Statement to display current sprite animation on screen
self.image = self.transformed_rightRun[self.index]
# Create player rectangle
self.rect = self.image.get_rect()
# Get x coordinate
self.rect.x = x
# Get y coordinate
self.rect.y = y
# Width and height for rectangle
self.width = self.image.get_width()
self.height = self.image.get_height()
# Set velocity in y direction to 0
self.vel_y = 0
# Player jump
self.jumped = False
# Player direction
self.direction = 0
# Check if player is in air
self.in_air = True
# Class for enemies
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
# Calling constructor from super class
pygame.sprite.Sprite.__init__(self)
# Load and scale bat images
self.image = pygame.image.load('Assets/Images/Sprites/Bat/Fly/fly2.png')
self.image = pygame.transform.scale(self.image, (50, 40))
# Flip bat image
self.left_image = pygame.transform.flip(self.image, True, False)
# Create rectangle
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# Variables for movement
self.move_direction = 1
self.move_counter = 0
def update(self):
# Move bats left and right
self.rect.x += self.move_direction
self.move_counter += 1
if abs(self.move_counter) > 100:
self.move_direction *= -1
self.move_counter *= -1
# Flip bat images
if self.move_direction == -1:
self.image = self.left_image
if self.move_direction == 1:
self.image = pygame.transform.flip(self.left_image, True, False)
# Draw bat rectangle to screen
pygame.draw.rect(screen, (255, 255, 255), self.rect, 2)
# Class for enemies
class Doors(pygame.sprite.Sprite):
def __init__(self, x, y):
# Calling constructor from super class
pygame.sprite.Sprite.__init__(self)
# Load and scale door images
self.image = pygame.image.load('Assets/Medieval Tileset/PNG/Objects/door4.png')
self.image = pygame.transform.scale(self.image, (80, 100))
# Create rectangle
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# Level 1 map
world_data1 = [
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 1, 1, 1, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 1, 5, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 7, 0, 1, 5, 5, 5, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
]
# Level 2 map
world_data2 = [
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 6, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
]
# Level 3 map
world_data3 = [
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 1, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
]
# Store level maps in list
levels = [
world_data1,
world_data2,
world_data3,
]
# Load in level data and create world
if current_level_index <= total_levels:
level = levels[current_level_index]
world = World(level)
# Create instance of button class
restart_button = Button(screen_width // 2 - 50, screen_height // 2 + 100, restart_img)
play_button = Button(screen_width // 2 - 550, screen_height // 2 - 220, play_img)
exit_button = Button(screen_width // 2 - 550, screen_height // 2 + 50, exit_img)
controls_button = Button(screen_width // 2 + 150, screen_height // 2 - 220, controls_img)
settings_button = Button(screen_width // 2 + 150, screen_height // 2 + 50, settings_img)
menu_button = Button(screen_width // 2 - 50, screen_height // 2 + 100, menu_img)
# Create instance of player class
player = Player(100, 800)
# main game loop
run = True
while run:
# Set internal clock
clock.tick(fps)
# Draw background to screen
screen.blit(background_img, (0, 0))
# Display buttons on main menu
if main_menu:
# If exit button is clicked, close game
if exit_button.draw():
run = False
# If play button is clicked, start game
if play_button.draw():
main_menu = False
controls_button.draw()
settings_button.draw()
else:
# Draw levels to screen
world.drawWorld()
# if the player dies, stop updating bats
if game_over == 0:
bat_group.update()
# Draw bats to screen
bat_group.draw(screen)
# Draw doors to screen
door_group.draw(screen)
# Draw player to screen and return game_over value
game_over = player.updatePlayer(game_over)
# if player dies, display restart button
if game_over == -1:
if restart_button.draw():
# Send player back to level 1
current_level_index = 0
reset_level(current_level_index)
game_over = 0
# If player has completed level, move to next level
if game_over == 1:
current_level_index += 1
if current_level_index <= total_levels:
reset_level(current_level_index)
game_over = 0
else:
# If player has completed final level, open main menu
if menu_button.draw():
main_menu = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
Any help would be greatly appreciated. Thank you!
Keep in mind that your main loop logic is run at each frame, so here, at each frame you run level 1, then if game over == 1 you run level2 etc, so everything is reset all the time. I think your problem is there.
You could define a state that would hold the current level and use this.
For example:
levels= ( # store your levels in some convenient structure
World(world_data1),
World(world_data2),
World(world_data2),
)
current_level_index = 0 # The level state, initalized with the index of the first level
game_over = 0
while True:
level = levels[current_level_index] # use your state to get the level instead of naming it directly
level.drawWorld()
# whatever you need to do to update your level logic, move things etc
if game_over == 1:
# This just is a simplistic example implementation to illustrate a change of level
current_level_index += 1
This is just a trivial example but you can try to structure your code in this kind of way.

Count number of multiples against every power of 4

Given a number, n, I need to efficiently find how many times this number is a multiple of all powers of 4 less than the given number.
For examples:
16 is a multiple of 4, and 16, so the result would be 2.
64 is a multiple of 4, 16, and 64, so the result would be 3.
256 is a multiple of 4, 16, 64, and 256, so the result would be 4.
14 is not a multiple of any power of 4, so the result would be 0.
35 is not a multiple of any power of 4, so the result would be 0.
Bitwise operations are preferred, and this is in a very tight loop so it is inside of a bottleneck that needs to be efficient. My code at the moment is the obvious answer, but I have to believe there is something more mathematical that can figure out the result in less steps:
power = 4;
while (power < n) {
result += !(n & (power - 1));
power *= 4;
}
You could use logarithms. A quick Google search for "fast log2 c++" brought up a pretty long list of ideas. Then your answer is log2(x)/2, and you'd have to find some way to make sure that your result is a whole number if you only want an answer for exact powers of 4.
If you are programming for an x86 processor, you can use BitScanForward & BitScanReverse to find the set bit, and use it to compute log2. The following code works in Visual Studio, for GCC or others, there are other ways to do inline assembly.
uint32_t exact_power_of_4_scan(uint32_t num)
{
unsigned long reverse;
unsigned long forward;
if (!_BitScanReverse(&reverse, num)) return 0;
_BitScanForward(&forward, num);
if (reverse != forward) return 0; // makes sure only a single bit is set
if (reverse & 0x1) return 0; // only want every other power of 2
return reverse / 2;
}
If you need a portable solution, table lookup might be the way to go, but is more complicated.
uint8_t not_single_bit[256] = {
1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
uint8_t log2_table[256] = {
0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
uint32_t exact_power_of_2(uint32_t num)
{
auto a = not_single_bit[num & 0xff];
auto b = not_single_bit[(num >> 8) & 0xff];
auto c = not_single_bit[(num >> 16) & 0xff];
auto d = not_single_bit[(num >> 24) & 0xff];
if (a + b + c + d != 3) {
return 0;
}
if (!a) {
return log2_table[num & 0xff];
}
if (!b) {
return log2_table[(num >> 8) & 0xff] + 8;
}
if (!c) {
return log2_table[(num >> 16) & 0xff] + 16;
}
return log2_table[(num >> 24) & 0xff] + 24;
}
uint32_t exact_power_of_4(uint32_t num)
{
auto ret = exact_power_of_2(num);
if (ret & 0x1) return 0;
return ret / 2;
}
Both are linear algorithms. The first will probably beat out looping for almost any value of num, but I haven't tested it. The second is probably only good for largish nums.
The mathematics would be to keep dividing by 4 until the result is no longer divisible by 4.
If you really want to do it with bitwise operations, techniques here can be used to count the number of trailing zero bits (i.e. the number of times a value is divisible by 2). Those can be adjusted to count pairs of trailing bits (i.e. divisibility by a power of 4 rather than 2).
Note that you will need to work with unsigned values to avoid certain cases of undefined or unspecified behaviours.
I would dispute your assertion that bitwise operations will make for a more efficient solution. It is not a given without testing, particularly with modern compilers.

Why is the size and values of this OpenCV Matrix incorrect?

I use the following function to return a weight matrix of values between 0 and 1 depending on how close to the center a particular matrix position is. Also after a threshold the values are all 1 (it is like plateau with the points closer to center having value 1 and points away from center after a threshold of distance linearly fall from 1 to 0 at the edges)?
cv::Mat2f getWeightsMatrix(int N, int M, float r){
cv::Mat2f weights = cv::Mat2f(N,M);
int i,j;
for(i=0;i<N;i++){
for(j=0;j<M;j++){
if(i<=floor(N*(1-r)/2)){
if(j<=floor(M*(1-r)/2)){
weights[i][j]=((float)(i/N-j/M)/(1-r));
}
else{
weights[i][j]=(2*(float)(i/N)/(1-r));
}
}
else if (i>=floor(N*(1+r)/2)){
if(j>=floor(M*(1+r)/2)){
weights[i][j]=(((float)((N-i)/N))-((float)((M-j)/M)))/(1-r);
}
else{
weights[i][j]=(2*(float)((N-i)/N)/(1-r));
}
}
else{
if(j<=floor(M*(1-r)/2)){
weights[i][j]=(2*(float)(j/M)/(1-r));
}
else if(j>=floor(M*(1+r)/2)){
weights[i][j]=(2*(float)((M-j)/M)/(1-r));
}
else{
weights[i][j]=1;
}
}
}
}
cout << weights << endl;
return weights;
}
Now my problem is that I am having some casting issues and only values 0 and 1 are being returned (no floats). Also my matrix size displayed by the cout is 20x10 when I call the function with N=10, M=10 and r=0.5.
Please helP!
EDIT: This is the output
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Your matrix consists only if integers because when you do basic operations on integers, the results gets rounded automatically.
For example: when you write
weights[i][j]=((float)(i/N-j/M)/(1-r));
The result of i/N is rounded to a integer, j/M is also rounded to an integer, and finally, the division by (1-r) is also rounded. Your (float) cast is a good idea but it's applied too late.
You can do several things:
Cast inside elementary operations, for instance, float(i)/N instead of i/N
Use float numbers instead of integers: write 1.0 instead of 1
Use floats inside your loops and statements
For example:
for(float i = 0; i < N-0.5; i++) {
for(float j = 0; j < M-0.5; j++) {
if(i <= floor(N*(1.0-r)/2.0)) {
// ...
It's important you understand that because of floating point precision, a test such as i < N might or might not pass when float i = N. This is why I did a little trick by substracting 0.5 from your loop bounds N and M.

Directx mesh vertices problem

I use DirectX to create a boxmesh,and I want to get the vertices position in the mesh,
but I find the 24 vertices are wrong!
or is there any way to use the 24 vertices???
here is my code
D3DXCreateBox(pd3dDevice,2,2,2,&g_model,NULL);
DWORD size=g_model->GetNumVertices();g_model->GetVertexBuffer(&Points);
Points->Lock(0,0,(void**)&v,0);
for(int i=0;i<size;i++)
{
D3DXVECTOR3 vertcle(v[i].x,v[i].y,v[i].z);
Pos.push_back(vertcle);
};
Points->Unlock();
The vectorPos is this:
Pos[24]({-1, -1, -1},{-1, 0, 0},{-1, -1, 1},{-1, 0, 0},{-1, 1, 1},{-1, 0, 0},{-1, 1, -1},{-1, 0, 0},{-1, 1, -1},{0, 1, 0},{-1, 1, 1},{0, 1, 0},{1, 1, 1},{0, 1, 0},{1, 1, -1},{0, 1, 0},{1, 1, -1},{1, 0, 0},{1, 1, 1},{1, 0, 0},{1, -1, 1},{1, 0, 0},{1, -1, -1},{1, 0, 0}) std::vector<D3DXVECTOR3,std::allocator<D3DXVECTOR3> >
you can notice some position are wrong(-1,0,0)....
Your vertex buffer contains normals as well as positions -- The odd vectors are the normals.
Try:
for(int i=0;i<size;i++)
{
D3DXVECTOR3 vertcle(v[2*i].x,v[2*i].y,v[2*i].z);
Pos.push_back(vertcle);
}

d opengl custom vs fixed-pipeline matrix weirdness

I have recently been working on shifting over to handling my matrix controls myself, so that my engine will be ready to shift over to a 4.0+ context, though currently I am using a 2.1 context with Derelict. I have tried all kinds of matrix calcs and nothing seems to work with my shader(nothing on screen except for FPS counter unless I switch back to fixed-pipe, or if I switch the vs to set gl_Position = vec4(position,1.0);). Even when I grab the values that OpenGL normally sets and put them into it I get the same.
I added print out of both my matrix and the one that the fixed-pipeline returned to the draw calls and the output is IDENTICAL. I've already checked and double checked my shader code, so I'm pretty lost as to from where this bug is coming.
This happens on both OSX and Windows. I have a glGetError() check every draw call and am not getting any errors. Shaders link and validate with out warning or error.
code for uniform loading:
glUniformMatrix4fv(ModelViewLoc,1, GL_FALSE ,modelview);
glUniformMatrix4fv(ProjectionLoc,1, GL_FALSE ,projection);
Vertex Shader:
#version 120
//layout(location = 0) in vec3 position;
attribute vec3 position;
uniform mat4 ModelView;
uniform mat4 Projection;
void main()
{
mat4 mvp = Projection*ModelView;
gl_Position = mvp * vec4(position,1.0);
//gl_Position = vec4(position,1.0);
}
Fragment Shader:
#version 120
uniform float slider;
void main()
{
vec4 diffuse = vec4(vec3(slider),1.0);
gl_FragColor = diffuse;
}
debug output:
Model 1:
OpenGL ModelView: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2, -2, -8, 1]
mine: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2, -2, -8, 1]
OpenGL Projection:[1.30323, 0, 0, 0, 0, 1.30323, 0, 0, 0, 0, -1.0002, -1, 0, 0, -0.20002, 0]
mine: [1.30323, 0, 0, 0, 0, 1.30323, 0, 0, 0, 0, -1.0002, -1, 0, 0, -0.20002, 0]
Model 2:
OpenGL ModelView: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 2, -8, 1]
mine: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 2, -8, 1]
OpenGL Projection:[1.30323, 0, 0, 0, 0, 1.30323, 0, 0, 0, 0, -1.0002, -1, 0, 0, -0.20002, 0]
mine: [1.30323, 0, 0, 0, 0, 1.30323, 0, 0, 0, 0, -1.0002, -1, 0, 0, -0.20002, 0]
*UPDATE*I have released the code for matrix lib # github.com/mclark4386/DMath See anything there?^^;