#!BPY

"""
Name: 'City Block Generator'
Blender: 248
Group: 'Add'
Tooltip: 'Create a simple city block'
"""

__author__ = "Johan Badenhorst"
__url__ = ("http://wiki.blender.org/index.php/Scripts/Manual/Wizards/City_Block_Generator")
__version__ = "0.5 Beta"

__bpydoc__ = """\

Usage:
This Script Creates blocks of "Buildings".
There are many variables that can be set.
The Buildings are joined as 1 mesh.
Low poly & quick to make.
this script is good also for games model creation.
Experimenting is the key. 

"""
 # City Block Generator

 # Version 
 
 # --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Johan Badenhorst
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# -------------------------------------------------------------------------

import random
from random import *
from Blender.BGL import *
from Blender.Draw import *
import Blender
from Blender import NMesh

def MakeBuilding(X, Y, Z, L, W, H):

   BMesh = NMesh.GetRaw()
    # Building vertices
   BVerts = ([X - L/2, Y - W/2, Z], 
             [X + L/2, Y - W/2, Z],
             [X + L/2, Y + W/2, Z], 
             [X - L/2, Y + W/2, Z], 

             [X - L/2, Y - W/2, H], 
             [X + L/2, Y - W/2, H], 
             [X + L/2, Y + W/2, H], 
             [X - L/2, Y + W/2, H])

   for V in BVerts:
      BMesh.verts.append(NMesh.Vert(V[0], V[1], V[2]))

    # Roof
   BFace = NMesh.Face()
   FaceVerts = 3, 2, 1, 0
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

    # Sides

   BFace = NMesh.Face()
   FaceVerts = 0, 1, 5, 4
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

   BFace = NMesh.Face()
   FaceVerts = 2, 3, 7, 6
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

   BFace = NMesh.Face()
   FaceVerts = 4, 7, 3, 0	
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

   BFace = NMesh.Face()
   FaceVerts = 1, 2, 6, 5
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

    # Floor
   BFace = NMesh.Face()
   FaceVerts = 4, 5, 6, 7
   for i in FaceVerts:
      BFace.v.append(BMesh.verts[i])
   BMesh.faces.append(BFace)

   BMesh.hasFaceUV(1)
   BMesh.update(1)   
   return BMesh

def MakeCluster(X, Y, Z, CHt):

   CMesh = NMesh.GetRaw()
   BW = random() * 0.25 + 0.25
   BL = random() * 0.25 + 0.25
   BH = random() * 0.5 + CHt 
   BMesh = MakeBuilding(X - 0.25, Y - 0.25, Z, BL, BW, BH) 

   for vert in BMesh.verts: 
      CMesh.verts.append(vert)
   for face in BMesh.faces: 
      CMesh.faces.append(face)

   BW = random() * 0.25 + 0.25
   BL = random() * 0.25 + 0.25
   BH = random() * 0.5 + CHt 
   BMesh = MakeBuilding(X - 0.25, Y + 0.25, Z, BL, BW, BH) 

   for vert in BMesh.verts: 
      CMesh.verts.append(vert)
   for face in BMesh.faces: 
      CMesh.faces.append(face)

   BW = random() * 0.25 + 0.25
   BL = random() * 0.25 + 0.25
   BH = random() * 0.5 + CHt 
   BMesh = MakeBuilding(X + 0.25, Y + 0.25, Z, BL, BW, BH) 

   for vert in BMesh.verts: 
      CMesh.verts.append(vert)
   for face in BMesh.faces: 
      CMesh.faces.append(face)

   BW = random() * 0.25 + 0.25
   BL = random() * 0.25 + 0.25
   BH = random() * 0.5 + CHt 
   BMesh = MakeBuilding(X + 0.25, Y - 0.25, Z, BL, BW, BH) 

   for vert in BMesh.verts: 
      CMesh.verts.append(vert)
   for face in BMesh.faces: 
      CMesh.faces.append(face)

   return CMesh
        
def MakeBlock(L, W, H, SH, CF, CH, BH):
    # Main Mesh
   BlockMesh = NMesh.GetRaw()
    # Create Paving
   BMesh = MakeBuilding(0, 0, -SH, L, W, 0.0)
   for vert in BMesh.verts: 
      BlockMesh.verts.append(vert)
   for face in BMesh.faces: 
      BlockMesh.faces.append(face)

   LL = - (L/2)
   LH =   L/2
   WL = - (W/2)
   WH =   W/2

   for i in range(LL , LH):
      for j in range(WL , WH):

          # Location
         BX = i + 0.5
         BY = j + 0.5
 
          # Proportions
         BW = 0.5 + random() * 0.5
         BL = 0.5 + random() * 0.5
         BHt = ((random() * BH) + BH)  

         IsCluster = random()
         if IsCluster <= CF:
            BMesh = MakeCluster(BX, BY, 0, CH)
         else:
            BMesh = MakeBuilding(BX, BY, 0, BW, BL, BHt)

         for vert in BMesh.verts: 
            BlockMesh.verts.append(vert)
         for face in BMesh.faces: 
            BlockMesh.faces.append(face)
   NMesh.PutRaw(BlockMesh)
   Blender.Redraw()

 # ------ GUI ------

 # Draw a group box
def GroupBox(x,y, w, h, r, g, b):
   glColor3f(0.0, 0.0, 0.0)
   glRecti(x, y, w, h)
   glColor3f(r, g, b)
   glRecti(x + 1, y + 1, w - 1, h - 1)
      
 # Events
PExit       = 1
PCreate     = 2
TClust      = 3
TOne        = 4
TSel        = 5
Slide       = 6

 # Controls
HasClust   = Create(1)
IsOne      = Create(0)
IsSel      = Create(0)
IsOneLight = Create(0)
CF = Create(0.5)
BL = Create(2)
BW = Create(4)
CH = Create(0.5)
BH = Create(0.5)

def GUI():
   global HasClust, CF, BL, BW, BH, CH, Slide
 
   glClearColor(0.8, 0.8, 0.8, 1.0)
   glClear(GL_COLOR_BUFFER_BIT)

   GroupBox(11, 185, 147, 211, 0.9, 0.9, 0.9)
   GroupBox(13, 187, 145, 209, 0.7, 0.7, 0.7)

   glColor3f(0.0, 0.0, 0.0)
   glRasterPos2i(23, 194)
   Text("City Block Generator")

   glColor3f(0.0, 0.0, 0.0)
   glRasterPos2i(123, 118)
   Text("Cluster Frequency")
   GroupBox(20, 85, 310, 115, 0.7, 0.7, 0.7)
   HasClust = Toggle("Clusters", TClust, 25, 90, 80, 20, HasClust.val)
   CF = Slider("CF: ", Slide, 110, 90, 195, 20, CF.val, 0.0, 1.0, 0)

   glColor3f(0.0, 0.0, 0.0)
   glRasterPos2i(123, 168)
   Text("Block Dimensions")
   GroupBox(20, 135, 310, 165, 0.7, 0.7, 0.7)
   BL = Slider("Len: ", Slide, 25, 140, 138, 20, BL.val, 2, 10, 0)
   BW = Slider("Wid: ", Slide, 167, 140, 138, 20, BW.val, 2, 10, 0)

   glColor3f(0.0, 0.0, 0.0)
   glRasterPos2i(123, 68)
   Text("Building height")
   GroupBox(20, 35, 310, 65, 0.7, 0.7, 0.7)
   BH = Slider("Bld: ", Slide, 25, 40, 138, 20, BH.val, 0.2, 2.0, 0)
   CH = Slider("Clstr: ", Slide, 167, 40, 138, 20, CH.val, 0.2, 1.0, 0)

   Button("Create", PCreate, 200, 5, 50, 20)
   Button("Exit", PExit, 260, 5, 50, 20)

def Event(evt, val):
   if not val:
      if evt == QKEY:
         Exit()


def BEvent(evt):
   global HasClust, CF, BL, BW, BH, CH

   if evt == PCreate:
      ClustFreq = float(HasClust.val * CF.val)
      MakeBlock(BL.val, BW.val, 3.0, 0.1, ClustFreq, CH.val, BH.val)
 
   if evt == PExit:
      Exit() 

   if evt == Slide:
      Register(GUI, Event, BEvent)

   if evt == TClust:
      Register(GUI, Event, BEvent)

      
Register(GUI, Event, BEvent)

Blender.Redraw()  