removed doc_browser.py - since it covers ~half the BPY api, not documenting any of blenders data types.

replaced with a help_bpy_api.py, that opens a web browser at the Blender Python API page.
Camera.c - added a veriable .angle to camera, same as .lens but adjusts the camera angle in degrees (like the D button)
export_fbx.py - use the the camera angle property.
object_cookie_cutter.py - use PointInTriangle2D rather then own function.
buttons_shading.c - added OB: and tooltip to object world mapping.
interface_draw.c - (Simple theme) text buttons looked exactly like normal buttons (more confusing when they had no text), made the text and ID buttons render inset so you can tell them apart.
This commit is contained in:
Campbell Barton 2007-04-28 17:21:00 +00:00
parent 6e27e1b6eb
commit 1d181b9108
8 changed files with 128 additions and 512 deletions

@ -1,467 +0,0 @@
#!BPY
"""
Name: 'BPy Doc Browser'
Blender: 232
Group: 'System'
Tip: 'Browse BPython (scripting API) modules doc strings.'
"""
__author__ = "Daniel Dunbar"
__url__ = ("blender", "elysiun")
__version__ = "1.0"
__bpydoc__ = """\
The "Doc Browser" lets users navigate the documentation strings of part of
the Blender Python API.
It doesn't give access yet to object method functions and variables, only to
module functions, but still it is a handy reference.
Hotkeys:<br>
Page Up / Page Down: scroll 5 lines at a time;<br>
Up / Down arrow keys or mouse wheel: scroll one line at a time.
Notes:<br>
Everyone interested in the bpython api is also invited to read "The Blender
Python API Reference" doc, available online ("Python Scripting Reference"
entry in Blender's Help menu).
"""
# $Id$
#
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2004: Daniel Dunbar, ddunbar _at_ diads.com
#
# 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 *****
# --------------------------------------------------------------------------
#####
# Blender help browser
# By Daniel Dunbar,
#
# This should function as a self-explanatory (interface, not code)
# (mostly) help browser. The code is wacky and nasty and or fun,
# but mainly bad, just cause it works doesn't mean its readable!
#
# TEEHEE!
#
# The row_draw function could easily be made into a more generic
# and usefull table drawing function...
#
import Blender
from types import ListType, IntType, FloatType, StringType, ModuleType
from Blender.Draw import *
from Blender.BGL import *
# Simple version check, since I use the
# buffer calls... DONT use this code,
# assume everyone has 1.73+, and force
# them to upgrade if they dont
try:
a= BufList
version= 172
except:
version= 173
# I could have used the split from the string module,
# but some people might not have it
def split(str, on):
out= [""]
for s in str:
if s in on: out.append("")
else: out[-1]= out[-1]+s
if out[-1]=="": del(out[-1])
return out
last_sort= 1; direction= 1
def sort_browselist(type):
global browselist
global last_sort, direction
if (type==last_sort): direction= -direction
else: direction= 1
last_sort= type
if (direction==1):
def byname(x, y): return cmp(x[0],y[0]);
def bytype(x, y): return cmp(x[1],y[1])
def bydata(x, y): return cmp(x[2],y[2])
else:
def byname(x, y): return cmp(y[0],x[0]);
def bytype(x, y): return cmp(y[1],x[1])
def bydata(x, y): return cmp(y[2],x[2])
if (type==1): browselist.sort(byname)
elif (type==2): browselist.sort(bytype)
elif (type==3): browselist.sort(bydata)
selected= -1
def view_doc(num):
global selected, selected_page
if (selected==num): selected= -1
else: selected= num
selected_page= 0
function_filter= 0
def toggle_function_filter():
global function_filter
function_filter= not function_filter
make_browselist()
def view_page(dir):
global selected_page
selected_page= selected_page + dir
browse_scrollstart= 0
def browse_module(num):
global browsing, selected, browse_scrollstart
# cant go back from Blender
if browsing.val == 'Blender' and num == -1:
return
if (num>=0): newstr= browsing.val + "." + browselist[num][0]
else:
modules= split(browsing.val, ".")
newstr= ""
for m in modules[:-1]:
newstr= newstr+m
try:
browsing= Create(newstr)
make_browselist()
except:
browsing= Create('Blender')
make_browselist()
browse_scrollstart= 0
scrolling= 0
selected= -1
def make_browselist():
global browselist
try:
module= eval(browsing.val)
except:
Blender.Draw.PupMenu('Error%t|Module is invalid')
browsing.val = 'Blender'
return
browselist= []
items= dir(module)
for item_name in items:
if (item_name[:2]=='__'): continue
data= [item_name, 'None', '', '']
item= eval(item_name,module.__dict__)
t= type(item)
if (t==IntType): data[1]= 'Int'; data[2]= `item`
elif (t==FloatType): data[1]= 'Float'; data[2]= `item`
elif (t==StringType): data[1]= 'String'
elif (t==ModuleType): data[1]= 'Module'
elif (callable(item)):
data[1]= 'Function'
doc= item.__doc__
if (doc): data[3]= doc
if (function_filter and data[1]!='Function'): continue
browselist.append(data)
browsing= Create('Blender')
make_browselist()
BROWSE_EVT= 1
SORT_BYNAME= 2
SORT_BYTYPE= 3
SORT_BYDATA= 4
DOC_PAGE_UP= 5
DOC_PAGE_DOWN= 6
BACK_MODULE= 7
CLOSE_VIEW= 8
FILTER_DISPLAY= 9
#SCROLLBAR= 10
VIEW_DOC= 100
BROWSE_MODULE= 10000
scr= Create(0)
browse_scrollstart= 0
winrect= [0.0, 0.0, 0.0, 0.0]
def draw():
global browsing, winrect, scr, browse_scrollstart
# Blender doesn't give us direct access to
# the window size yet, but it does set the
# GL scissor box for it, so we can get the
# size from that.
if (version<173):
size= Buffer(GL_FLOAT, None, 4)
glGetFloat(GL_SCISSOR_BOX, size)
size= BufList(size)
else:
size= Buffer(GL_FLOAT, 4)
glGetFloatv(GL_SCISSOR_BOX, size)
size= size.list
winrect= size[:]
size[0]= size[1]= 0.0
# Shrink the size to make a nice frame
# (also a good technique so you can be sure you are clipping things properly)
size[0], size[1]= int(size[0]+10), int(size[1]+10)
size[2], size[3]= int(size[2]-12), int(size[3]-10)
glClearColor(0.6, 0.5, 0.3, 0.0)
glClear(GL_COLOR_BUFFER_BIT)
# The frame
glColor3f(0.4, 0.5, 0.2)
glRectf(size[0], size[1], size[2], size[3])
# Window header
glColor3f(0.2, 0.2, 0.4)
glRectf(size[0], size[3]-25, size[2], size[3])
glColor3f(0.6, 0.6, 0.6)
glRasterPos2f(size[0]+15, size[3]-17)
Text("Zr's Help Browser")
Button("Filter", FILTER_DISPLAY, size[2]-400, size[3]-22, 45, 18)
Button("Back", BACK_MODULE, size[2]-300, size[3]-22, 45, 18)
browsing= String("Browse: ", BROWSE_EVT, size[2]-250, size[3]-22, 245, 18, browsing.val, 30)
# The real table
def row_draw(rect, data, cols, cell_colors, text_colors):
if (len(data)!=len(cols)):
print "Must have same length data and columns"
return
if (type(cell_colors)!=ListType): cell_colors= [cell_colors]
if (type(text_colors)!=ListType): text_colors= [text_colors]
sx= rect[0]
for i in range(len(data)):
d= data[i]
c= cols[i]
c, align= c[0], c[1]
if (type(c)==FloatType): c= c*(rect[2]-rect[0])
ex= sx + c
color= cell_colors[i%len(cell_colors)]
apply(glColor3f, color)
glRectf(sx, rect[1], ex, rect[3])
color= text_colors[i%len(text_colors)]
apply(glColor3f, color)
if (type(d)==StringType):
str_width= len(d)*8
if (align=='left'): glRasterPos2f(sx+3, rect[1]+5)
elif (align=='center'): glRasterPos2f((sx+ex)/2 - str_width/2 +3, rect[1]+5)
elif (align=='right'): glRasterPos2f(ex - str_width -3, rect[1]+5)
Text(d)
else:
d(map(int,[sx, rect[1], ex, rect[3]]))
sx= ex
# Some colors
black= (0.0, 0.0, 0.0)
white= (1.0, 1.0, 1.0)
red= (0.8, 0.1, 0.1)
gray0= (0.17, 0.17, 0.17)
gray1= (0.25, 0.25, 0.25)
gray2= (0.33, 0.33, 0.33)
gray3= (0.41, 0.41, 0.41)
gray4= (0.49, 0.49, 0.49)
gray5= (0.57, 0.57, 0.57)
gray6= (0.65, 0.65, 0.65)
cols= [[.3, 'left'], [.2, 'left'], [.4, 'right'], [.1, 'center']]
header= [size[0]+20, size[3]-60, size[2]-40, size[3]-40]
def sort_byname(co): Button("Name",SORT_BYNAME, co[0]+3, co[1], co[2]-co[0]-4, 19)
def sort_bytype(co): Button("Type",SORT_BYTYPE, co[0]+3, co[1], co[2]-co[0]-4, 19)
def sort_bydata(co): Button("Data",SORT_BYDATA, co[0]+3, co[1], co[2]-co[0]-4, 19)
row_draw(header, [sort_byname, sort_bytype, sort_bydata,'Link'], cols, [gray0, gray1], gray6)
if (selected!=-1):
table= [size[0]+20, size[1]+220, size[2]-40, size[3]-60]
else:
table= [size[0]+20, size[1]+20, size[2]-40, size[3]-60]
row_height= 25
items= (table[3]-table[1])/row_height
items= 10
if (items>len(browselist)): items= len(browselist)
end= len(browselist)-items
#if (end>0):
# scr= Scrollbar(SCROLLBAR, table[2]+5, table[1], 20, table[3]-table[1], scr.val, 0.0, end, 0, "Page Up/Down scrolls list.")
row= table
row[1]= row[3]-row_height
start= browse_scrollstart
if (start+items>len(browselist)): items= len(browselist)-start
for i in range(items):
i= start+i
data= browselist[i][:]
if (i%2): colors= [gray1, gray2]
else: colors= [gray2, gray3]
# Strange pythonic code
def view_doc(co,num=i):
Button("Doc",VIEW_DOC+num, co[0]+3, co[1]+2, co[2]-co[0]-4, 19)
def browse_module(co,num=i):
Button("Browse",BROWSE_MODULE+num, co[0]+3, co[1]+2, co[2]-co[0]-4, 19)
if (data[1]=='Function'):
if data[3]:
data[3]= view_doc
tcolor= black
else:
tcolor= red
data[2]= 'NO DOC STRING'
data[3]= ''
else:
if (data[1]=='Module'): data[3]= browse_module
else: data[3]= ''
tcolor= black
row_draw(row, data, cols, colors, tcolor)
row[1]= row[1]-row_height
row[3]= row[3]-row_height
if (selected!=-1):
table= [size[0]+20, size[1]+20, size[2]-40, size[1]+180]
apply(glColor3f, gray5)
glRectf(table[0], table[3], table[2], table[3]+20)
apply(glColor3f, gray2)
glRectf(table[0], table[1], table[2], table[3])
apply(glColor3f, black)
glRasterPos2f(table[0]+3, table[3]+5)
Text("Function: " + browsing.val + "." + browselist[selected][0])
Button("Close", CLOSE_VIEW, table[2]-50, table[3], 45, 18)
row_height= 20
view_lines= int((table[3]-table[1])/row_height)-1
lines= split(browselist[selected][3], "\n")
doc_lines= len(lines)
sindex= view_lines*selected_page
eindex= view_lines*(selected_page+1)
if (sindex>0):
sindex= sindex-1
eindex= eindex-1
lines= lines[sindex:eindex]
y= table[3]-20
for line in lines:
glRasterPos2f(table[0]+3, y)
Text(line)
y= y-20
if (sindex): Button("Page up", DOC_PAGE_UP, table[2]-100, table[3]-20, 90, 18)
if (eindex<doc_lines): Button("Page down", DOC_PAGE_DOWN, table[2]-100, table[1]+5, 90, 18)
lmouse= [0, 0]
def fit_scroll():
global browse_scrollstart, browselist
if (browse_scrollstart<0): browse_scrollstart= 0
elif (browse_scrollstart>=len(browselist)): browse_scrollstart= len(browselist)-1
def event(evt, val):
global browse_scrollstart
if (evt==QKEY or evt==ESCKEY): Exit()
elif val:
if (evt in [PAGEUPKEY, PAGEDOWNKEY]):
if (evt==PAGEUPKEY): browse_scrollstart= browse_scrollstart-5
else: browse_scrollstart= browse_scrollstart+5
elif (evt in [UPARROWKEY, WHEELUPMOUSE]):
browse_scrollstart -= 1
elif (evt in [DOWNARROWKEY, WHEELDOWNMOUSE]):
browse_scrollstart += 1
else: return
fit_scroll()
Redraw()
def bevent(evt):
if (evt==BROWSE_EVT): make_browselist()
elif (evt==SORT_BYNAME): sort_browselist(1)
elif (evt==SORT_BYTYPE): sort_browselist(2)
elif (evt==SORT_BYDATA): sort_browselist(3)
elif (evt==DOC_PAGE_UP): view_page(-1)
elif (evt==DOC_PAGE_DOWN): view_page(1)
elif (evt==BACK_MODULE): browse_module(-1)
elif (evt==CLOSE_VIEW): view_doc(-1)
elif (evt==FILTER_DISPLAY): toggle_function_filter()
#elif (evt==SCROLLBAR):
# global browse_scrollstart
# browse_scrollstart= int(scr.val)
elif (evt>=BROWSE_MODULE): browse_module(evt-BROWSE_MODULE)
elif (evt>=VIEW_DOC): view_doc(evt-VIEW_DOC)
Redraw()
Register(draw, event, bevent)

@ -381,14 +381,12 @@ def write_scene(file, sce, world):
data = ob.data
angle= 360.0 * atan(16.0/data.lens) / pi;
file.write('\n\tModel: "Model::%s", "Camera" {' % name )
file.write('\n\t\tVersion: 232')
loc, rot, scale, matrix, matrix_rot = write_object_props(ob)
file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0')
file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % angle)
file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle)
file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1')
file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1')
file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026')

@ -0,0 +1,41 @@
#!BPY
"""
Name: 'Blender/Python Scripting API'
Blender: 243
Group: 'Help'
Tooltip: 'The Blender Python API reference manual'
"""
__author__ = "Matt Ebb"
__url__ = ("blender", "elysiun")
__version__ = "1.0"
__bpydoc__ = """\
This script opens the user's default web browser at http://www.blender.org's
"Blenders Python API" page.
"""
# --------------------------------------------------------------------------
# Manual Help Menu Item
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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 Blender, webbrowser
version = str(int(Blender.Get('version')))
webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/index.html')

@ -53,6 +53,7 @@ from math import sqrt
import BPyMesh
Vector= Blender.Mathutils.Vector
LineIntersect2D= Blender.Geometry.LineIntersect2D
PointInTriangle2D= Blender.Geometry.PointInTriangle2D
# Auto class
def auto_class(slots):
@ -103,19 +104,14 @@ def point_in_bounds(pt, bounds):
return True
else:
return False
def point_in_poly2d(pt, fvco):
crazy_point= Vector(pt) # A point far outside the range of the terrain.
crazy_point.x= crazy_point.x - 10000000
#fvco= [v.co for v in face]
isect=0
for i in xrange(len(fvco)):
isect+= (LineIntersect2D(pt, crazy_point, fvco[i], fvco[i-1]) != None)
return isect%2 # odd number is an intersect which wouold be true (inside the face)
if PointInTriangle2D(pt, fvco[0], fvco[1], fvco[2]):
return True
if len(fvco) == 4:
if PointInTriangle2D(pt, fvco[0], fvco[2], fvco[3]):
return True
return False
# reuse me more.
def sorted_edge_indicies(ed):

@ -52,6 +52,7 @@
enum cam_consts {
EXPP_CAM_ATTR_LENS = 0,
EXPP_CAM_ATTR_ANGLE,
EXPP_CAM_ATTR_DOFDIST,
EXPP_CAM_ATTR_CLIPEND,
EXPP_CAM_ATTR_CLIPSTART,
@ -728,6 +729,9 @@ static PyObject *getFloatAttr( BPy_Camera *self, void *type )
case EXPP_CAM_ATTR_LENS:
param = cam->lens;
break;
case EXPP_CAM_ATTR_ANGLE:
param = 360.0f * atan(16.0f/cam->lens) / M_PI;
break;
case EXPP_CAM_ATTR_DOFDIST:
param = cam->YF_dofdist;
break;
@ -772,14 +776,19 @@ static int setFloatAttrClamp( BPy_Camera *self, PyObject *value, void *type )
float *param;
struct Camera *cam = self->camera;
float min, max;
int ret;
switch( (int)type ) {
case EXPP_CAM_ATTR_LENS:
min = 1.0;
max = 250.0;
param = &cam->lens;
break;
case EXPP_CAM_ATTR_ANGLE:
min = 7.323871;
max = 172.847331;
param = &cam->lens;
break;
case EXPP_CAM_ATTR_DOFDIST:
min = 0.0;
max = 5000.0;
@ -826,7 +835,14 @@ static int setFloatAttrClamp( BPy_Camera *self, PyObject *value, void *type )
"undefined type in setFloatAttrClamp" );
}
return EXPP_setFloatClamped( value, param, min, max );
ret = EXPP_setFloatClamped( value, param, min, max );
if (ret==0) {
if ((int)type == EXPP_CAM_ATTR_ANGLE) {
cam->lens = 16.0f / tan(M_PI*cam->lens/360.0f);
}
}
return ret;
}
@ -879,6 +895,11 @@ static PyGetSetDef BPy_Camera_getseters[] = {
(getter)getFloatAttr, (setter)setFloatAttrClamp,
"lens angle for perspective cameras",
(void *)EXPP_CAM_ATTR_LENS},
{"angle",
(getter)getFloatAttr, (setter)setFloatAttrClamp,
"lens angle for perspective cameras",
(void *)EXPP_CAM_ATTR_ANGLE},
{"scale",
(getter)getFloatAttr, (setter)setFloatAttrClamp,
"scale for ortho cameras",

@ -50,6 +50,7 @@ class Camera:
@ivar type: The Camera type: 'persp' or 'ortho'
@ivar mode: The mode flags: B{ORed value}: 'showLimits':1, 'showMist':2.
@ivar lens: The lens value in [1.0, 250.0], only relevant to *persp* cameras.
@ivar angle: The lens value in degrees [7.323871, 172.847331], only relevant to *persp* cameras.
@ivar scale: The scale value in [0.01, 1000.00], only relevant to *ortho* cameras.
@ivar clipStart: The clip start value in [0.0, 100.0].
@ivar clipEnd: The clip end value in [1.0, 5000.0].

@ -2045,7 +2045,7 @@ static void world_panel_texture(World *wrld)
uiDefButS(block, ROW, B_WORLDPRV, "Tube", 235,90,65,20, &(mtex->texco), 4.0, (float)TEXCO_H_TUBEMAP, 0, 0, "For 360 degree panorama sky, cylindrical mapped, only top half");
uiDefButS(block, ROW, B_WORLDPRV, "Object", 100,70,70,20, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_WORLDPRV, "", 170,70,130,20, &(mtex->object), "");
uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_WORLDPRV, "OB:", 170,70,130,20, &(mtex->object), "Object name to use for mapping");
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_WORLDPRV, "dX", 100,40,100,19, mtex->ofs, -20.0, 20.0, 10, 0, "Fine tunes texture mapping X coordinate");

@ -1207,16 +1207,17 @@ static void ui_draw_round(int type, int colorid, float asp, float x1, float y1,
static void ui_draw_minimal(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
/* too much space between buttons */
/*
x1+= asp;
x2-= asp;
y1+= asp;
y2-= asp;
*/
/* Less space between buttons looks nicer */
y2-= asp;
x2-= asp;
if (type==TEX || type==IDPOIN) {
x1+= asp;
x2-= (asp*2);
//y1+= asp;
y2-= asp;
} else {
/* Less space between buttons looks nicer */
y2-= asp;
x2-= asp;
}
/* paper */
if(flag & UI_SELECT) {
@ -1229,34 +1230,59 @@ static void ui_draw_minimal(int type, int colorid, float asp, float x1, float y1
}
glRectf(x1, y1, x2, y2);
if(flag & UI_SELECT) {
if (type==TEX || type==IDPOIN) {
BIF_ThemeColorShade(colorid, -60);
/* top */
fdrawline(x1, y2, x2, y2);
/* left */
fdrawline(x1, y1, x1, y2);
BIF_ThemeColorShade(colorid, +40);
/* below */
fdrawline(x1, y1, x2, y1);
/* right */
fdrawline(x2, y1, x2, y2);
}
else {
BIF_ThemeColorShade(colorid, +40);
/* top */
fdrawline(x1, y2, x2, y2);
/* left */
fdrawline(x1, y1, x1, y2);
BIF_ThemeColorShade(colorid, -60);
/* text underline, some */
BIF_ThemeColorShade(colorid, +50);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x8888);
fdrawline(x1+(asp*2), y1+(asp*3), x2-(asp*2), y1+(asp*3));
glDisable(GL_LINE_STIPPLE);
BIF_ThemeColorShade(colorid, +60);
/* below */
fdrawline(x1, y1, x2, y1);
/* right */
fdrawline(x2, y1, x2, y2);
} else {
if(flag & UI_SELECT) {
BIF_ThemeColorShade(colorid, -60);
/* top */
fdrawline(x1, y2, x2, y2);
/* left */
fdrawline(x1, y1, x1, y2);
BIF_ThemeColorShade(colorid, +40);
/* below */
fdrawline(x1, y1, x2, y1);
/* right */
fdrawline(x2, y1, x2, y2);
}
else {
BIF_ThemeColorShade(colorid, +40);
/* top */
fdrawline(x1, y2, x2, y2);
/* left */
fdrawline(x1, y1, x1, y2);
BIF_ThemeColorShade(colorid, -60);
/* below */
fdrawline(x1, y1, x2, y1);
/* right */
fdrawline(x2, y1, x2, y2);
}
}
/* special type decorations */