#White #Dark #txt #download

        
#!coding: utf-8
"""
Ce code montre que pour faire un jeu en 3D, une seule chose varie : le DESSIN
Ainsi un jeu purement 2D peut être affiché en 3D, comme ce casse brique.
Pour comparer la version 2D et la version 3D, regardez le code gl_brick_2D.py

On fait de la 3D grâce à OpenGL.
ATTENTION: Ce code utilise de la Vieille 3D (années 2000)
On parle d'OpenGL "version 2" ou de "fixed pipeline" ou "mode immédiat" ou "opengl sans shaders"
Il est vivement conseillé d'apprendre les shaders dès le début de votre apprentissage OpenGL
pour pouvoir faire de puissants effets modernes.
Il y a plein de fichier d'exemples pour les shaders sur le site.
Un très bon tutoriel d'opengl moderne (OpenGL 3 / OpenGL avec shaders) est :
learnopengl.com

Cependant, ce code est très utile pour comprendre les bases de la 3D et les matrices.
(Ou pour avoir vite fait un affichage)
"""
from __future__ import print_function, division

import pygame
import random

# importer la bibliothèque OpenGL !
from OpenGL.GL import *
from OpenGL.GLU import *

import sys
pygame.init()

def nouvel_ecran(W,H):
    e = pygame.display.set_mode([W,H], pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
    
    glViewport(0, 0, W, H)
    glEnable(GL_COLOR_MATERIAL)
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glEnable(GL_NORMALIZE)
    glShadeModel(GL_SMOOTH)
    glLight(GL_LIGHT0, GL_AMBIENT,  (0,0,0,1))
    glLight(GL_LIGHT0, GL_DIFFUSE,  (1,1,1,1))
    glLight(GL_LIGHT0, GL_SPECULAR,  (1,1,1,1))
        
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    
    return e

tx,ty = taille = [12*60, 500]
ecran = nouvel_ecran(tx, ty)

clock = pygame.time.Clock()

ROUGE = [255,0,0]
VERT = [0,255,0]
BLEU = [0,0,255]
JAUNE = [255,255,0]
BLANC = [255,255,255]
NOIR = [0, 0, 0]
ORANGE = [255, 153, 0]
BLEU_CLAIR = [135, 206, 250]

class Balle:
    pass

balles = []

for i in range(5):
    b = Balle()
    b.taille = 20
    b.x = random.randrange(700 - b.taille)
    b.y = 300 + random.randrange(200)
    b.sx = random.choice([-1,1])
    b.sy = random.choice([-1,1])
    balles.append(b)

class Brique:
    pass

briques = []

def creer_briques():

    for i in range(12):
        for j in range(5):
            r = Brique()
            r.vie = 3
            r.taille_x = 60
            r.taille_y = 30
            r.x = i * r.taille_x
            r.y = j * r.taille_y
            briques.append(r)

creer_briques()

def draw_cube():
    """
    from (0,0,0) to (1,1,1)
    faces are ccw (counter clockwise : sens contraire des aiguilles d'une montre)
    """
    glBegin(GL_TRIANGLES) # GL_QUADS is deprecated
    
    glNormal3f(0, 0, 1) # up
    glVertex3f(0, 0, 1)
    glVertex3f(1, 0, 1)
    glVertex3f(0, 1, 1)
    glVertex3f(1, 0, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(0, 1, 1) 
    
    glNormal3f(0, 0, -1) # down  
    glVertex3f(0, 0, 0)
    glVertex3f(0, 1, 0)
    glVertex3f(1, 0, 0)
    glVertex3f(0, 1, 0)
    glVertex3f(1, 1, 0)
    glVertex3f(1, 0, 0)
    
    glNormal3f(1, 0, 0) # right
    glVertex3f(1, 0, 0)
    glVertex3f(1, 1, 0)
    glVertex3f(1, 0, 1)
    glVertex3f(1, 1, 0)
    glVertex3f(1, 1, 1)
    glVertex3f(1, 0, 1)
    
    glNormal3f(-1, 0, 0) # left
    glVertex3f(0, 0, 0)
    glVertex3f(0, 0, 1)
    glVertex3f(0, 1, 0)
    glVertex3f(0, 0, 1)
    glVertex3f(0, 1, 1)
    glVertex3f(0, 1, 0)
    
    glNormal3f(0, 1, 0) # back
    glVertex3f(0, 1, 0)
    glVertex3f(0, 1, 1)
    glVertex3f(1, 1, 0)
    glVertex3f(0, 1, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, 1, 0)
    
    glNormal3f(0, -1, 0) # front
    glVertex3f(1, 0, 0)
    glVertex3f(1, 0, 1)
    glVertex3f(0, 0, 0)
    glVertex3f(1, 0, 1)
    glVertex3f(0, 0, 1)
    glVertex3f(0, 0, 0)
    
    glEnd()

t = 0

fini = 0
while fini == 0:
    # pour tous les événements qui se sont passsés depuis la dernière fois
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # si l'event est de type QUIT
            fini = 1 # on met fini à 1, ce qui va quitter la boucle à la fin de ce tick
        elif event.type == pygame.VIDEORESIZE:
            # on s'adapte à la nouvelle fenêtre
            ecran = nouvel_ecran(event.w, event.h) # re créer l'écran !
    
    # déplacement
    
    for b in balles:
        b.x += b.sx * 5
        b.y += b.sy * 5
        
        i = 0
        while i < len(briques):
            r = briques[i]
            if not(
                r.x > b.x + b.taille or
                r.y > b.y + b.taille or
                r.x + r.taille_x < b.x or
                r.y + r.taille_y < b.y
            ):
                b.x -= b.sx * 5
                b.y -= b.sy * 5
                
                dx = r.x - b.x if r.x > b.x else b.x - (r.x + r.taille_x)
                dy = r.y - b.y if r.y > b.y else b.y - (r.y + r.taille_y)
                if dx > dy:
                    b.sx *= -1
                else:
                    b.sy *= -1
                
                r.vie -= 1
                if r.vie == 0:
                    del briques[i]
                    i -= 1
                
            i += 1
        
        if b.x > tx - b.taille:
            b.sx = -1
        if b.x < 0:
            b.sx = 1
        if b.y > ty - b.taille:
            b.sy = -1
        if b.y < 0:
            b.sy = 1
    
    if len(briques) == 0:
        creer_briques()
    
    t += 1
    
    # dessin
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, 1.0 * tx / ty, 100, 2000) # fov 45°, ratio tx / ty, distance min : 100, distance max : 2000
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    
    # position et orientation de la camera :
    camera_x = tx/2 # au milieu de l'arène
    camera_y = -ty # derrière l'arène 
    camera_z = 700 # bien haut
    
    cible_camera_x, cible_camera_y = tx / 2, ty / 2 # regarde le milieu de l'arène
    cible_camera_z = 0 # regarde par terre
    
    gluLookAt(camera_x, camera_y, camera_z, cible_camera_x, cible_camera_y, cible_camera_z, 0,0,1)
    
    # position de la lampe :
    light_x, light_y = tx / 2, ty / 2 # lampe au milieu de l'arène
    light_z = 150 # un peu au dessus des briques (hauteur : 100)
    glLight(GL_LIGHT0, GL_POSITION,  [light_x, light_y, light_z, 1])
    
    # dessin du sol
    glColor3ubv(BLEU_CLAIR) # 3ubv signifie que l'on indique la couleur avec une liste de 3 int de 0 à 255
    glBegin(GL_TRIANGLES) # GL_QUADS is deprecated
    glNormal3f(0, 0, 1)
    glVertex3f(0, 0, 0)
    glVertex3f(tx, 0, 0)
    glVertex3f(0, ty, 0)
    glVertex3f(tx, 0, 0)
    glVertex3f(tx, ty, 0)
    glVertex3f(0, ty, 0)
    glEnd()
    
    # dessin des 4 côtés
    glColor3f(0.8, 0.8, 0.8) # 3f signifie que l'on indique la couleur avec 3 float (nombres réels / à virgule) entre 0 et 1
    
    glPushMatrix()
    glTranslatef(0, -50, 0)
    glScalef(tx, 50, 50)
    draw_cube()
    glPopMatrix()
    
    glPushMatrix()
    glTranslatef(0, ty, 0)
    glScalef(tx,50,50)
    draw_cube()
    glPopMatrix()
    
    glPushMatrix()
    glTranslatef(-50, 0, 0)
    glScalef(50, ty, 50)
    draw_cube()
    glPopMatrix()
    
    glPushMatrix()
    glTranslatef(tx, 0, 0)
    glScalef(50, ty, 50)
    draw_cube()
    glPopMatrix()
    
    # dessin des briques
    for r in briques:
        color = (ROUGE if r.vie == 3 else
                 VERT if r.vie == 2 else
                 JAUNE)
        
        glColor3ubv(color)
        
        glPushMatrix()
        d = 5
        glTranslatef(r.x + d, ty - (r.y + d) - (r.taille_y - 2*d), 0)
        glScalef(r.taille_x - 2*d, r.taille_y - 2*d, 100)
        draw_cube()
        
        glPopMatrix()
    
    # dessin des balles
    glColor3ubv(ORANGE)
    for b in balles:
        glPushMatrix()
        glTranslatef(b.x, ty - b.y - b.taille, 0)
        glScalef(b.taille, b.taille, b.taille)
        draw_cube()
        glPopMatrix()
    
    # dessin du repère en (0,0,100) (sans lighting)
    
    glDisable(GL_LIGHTING)
    glPushMatrix()
    glTranslatef(0,0,100)
    glScalef(50,50,50)
    
    glBegin(GL_LINES)
    glColor3ubv(ROUGE)
    glVertex3f(0, 0, 0)
    glVertex3f(1, 0, 0)
    glColor3ubv(VERT)
    glVertex3f(0, 0, 0)
    glVertex3f(0, 1, 0)
    glColor3ubv(BLEU)
    glVertex3f(0, 0, 0)
    glVertex3f(0, 0, 1)
    glEnd()
    
    glPointSize(5)
    
    glBegin(GL_POINTS)
    glColor3ubv(ROUGE)
    glVertex3f(1, 0, 0)
    glColor3ubv(VERT)
    glVertex3f(0, 1, 0)
    glColor3ubv(BLEU)
    glVertex3f(0, 0, 1)
    glEnd()
        
    glEnable(GL_LIGHTING)
    glPopMatrix()
    
    # appliquer les dessins
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()