home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Enigma Amiga Life 106
/
EnigmaAmiga106CD.iso
/
www
/
afc
/
afc-dir
/
vectworld_source.lha
/
Source
/
vectWorld.e
< prev
Wrap
Text File
|
1999-02-20
|
101KB
|
3,501 lines
/*
$VER: vectWorld V1.00 - by Andrea Galimberti - (C) Brighting Brain Brothers
Base Number: $8005
Description: this MODULE contains a SET OF instructions TO build 3D
Objects. These objects can be linked together in a World
OBJECT AND can be rendered in wireframe mode OR in filled
vectors mode.
Note: *pensare a come far diventare visibili le superfici che si scoprono
quando cancello quelle davanti.
*/
->/// Main docs
/*
@node main "AFC Module: vectWorld / Main"
** vectWorld V1.00 - Original By Andrea Galimberti **
Part of Amiga Foundation Classes
--- NO LONGER SUPPORTED ---
@{" Introduction " LINK world_intro} Important: don't skip this as usual.
@{" Author(s) Info " LINK author}
Requires: @{" nodemaster " LINK "nodemaster.guide/Main"}
Base: $8005
Sections: @{" vectWorld methods " LINK world_methods}
@{" Object_obj methods " LINK world_o_methods}
@{" Procedures " LINK world_procedures}
@{" ERROR TABLE " LINK Error_Table}
@endnode
@node world_methods "AFC module: vectWorld methods"
vectWorld methods:
COMMANDS BRIEF DESCRIPTION
-----------------------------------------------------------------------
@{" vectWorld() " LINK vectWorld} Initializes a world
@{" addobj() " LINK world_addobj} Create and add an object
@{" setobj() " LINK world_setobj} Only add an existing object
@{" getobj() " LINK world_getobj} Get a specified object
@{" delobj() " LINK world_delobj} Delete object
@{" unlinkobj() " LINK world_unlinkobj} Remove an object
@{" clearobj() " LINK world_clearobj} Clear an object
@{" setvertex() " LINK world_setvertex} Add vertex to object
@{" getvertex() " LINK world_getvertex} Get vertex of object
@{" fastsetvert() " LINK world_fastsetvert} Fast add vertex
@{" delvertex() " LINK world_delvertex} Delete vertex from object
@{" setline() " LINK world_setline} Add line to object
@{" getline() " LINK world_getline} Get line from object
@{" fastsetline() " LINK world_fastsetline} Fast add line
@{" delline() " LINK world_delline} Delete line from object
@{" setsurface() " LINK world_setsurface} Add surface to object
@{" getsurface() " LINK world_getsurface} Get surface from object
@{" delsurface() " LINK world_delsurface} Delete surface from object
@{" visible() " LINK world_visible} Switch on and off an object
@{" position() " LINK world_position} Move local axes of an object
@{" scale() " LINK world_scale} Scale an object
@{" applyobj() " LINK world_applyobj} Apply transformations to an object
@{" projection() " LINK world_projection} 3D -> 2D conversion
@{" getpoint() " LINK world_getpoint} Get projected pixel
@{" draw() " LINK world_draw} Draw wireframe (or points)
@{" init3D() " LINK world_init3d} Initialise filled vectors
@{" drawfill() " LINK world_drawfill} Draw filled vectors
@{" copyobj() " LINK world_copyobj} Copy two objects
@{" cloneobj() " LINK world_cloneobj} Duplicate an object
@{" setobserver() " LINK world_setobserver} Position observer
@{" setscale() " LINK world_setscale} Scale all objects
@{" settrasl() " LINK world_settrasl} Traslate all objects
@{" setrot() " LINK world_setrot} Rotate all objects
@{" setafterscale() " LINK world_setafterscale} Scale to fit screen
@{" setaftertrasl() " LINK world_setaftertrasl} Traslate origin of axes
@{" setdisplay() " LINK world_setdisplay} Set display features
@{" version() " LINK world_version} Version of vectWorld
@endnode
@node world_o_methods "AFC module: Object_obj methods"
Object_obj methods:
COMMANDS BRIEF DESCRIPTION
-----------------------------------------------------------------------
@{" object_obj() " LINK object_obj} Initializes an object
@{" clear() " LINK object_clear} Clear object
@{" name() " LINK object_name} Return object name
@{" setvertex() " LINK object_setvertex} Add vertex
@{" getvertex() " LINK object_getvertex} Get vertex
@{" fastsetvert() " LINK object_fastsetvert} Fast add vertex
@{" delvertex() " LINK object_delvertex} Delete vertex
@{" setline() " LINK object_setline} Add line
@{" getline() " LINK object_getline} Get line
@{" fastsetline() " LINK object_fastsetline} Fast add line
@{" delline() " LINK object_delline} Delete line
@{" setsurface() " LINK object_setsurface} Add surface
@{" getsurface() " LINK object_getsurface} Get surface
@{" delsurface() " LINK object_delsurface} Delete surface
@{" position() " LINK object_position} Move local axes
@{" scale() " LINK object_scale} Scale object
@{" apply() " LINK object_apply} Apply transformations
@{" projection() " LINK object_projection} Project single object
@{" getpoint() " LINK object_getpoint} Get projected pixel
@{" copy() " LINK object_copy} Copy object
@{" clone() " LINK object_clone} Duplicate object
@endnode
@node world_procedures "AFC module: Procedures"
Procedures:
COMMANDS BRIEF DESCRIPTION
-----------------------------------------------------------------------
@{" fillSinTable() " LINK world_fillsintable} Initialize table of sines
@{" limitangle() " LINK world_limitangle} Bound angle (0 - 360 degrees)
@{" crossprod() " LINK world_crossprod} Vector product
@{" dotprod() " LINK world_dotprod} Scalar product
@endnode
@node author "Author(s) Info"
Original By: Andrea Galimberti
E Version By: Andrea Galimberti
@endnode
@node world_intro "AFC module: vectWorld / Introduction"
vectWorld
------------
This Class contains instructions to create, manipulate and draw three
dimensional objects: they can be rotated, scaled and drawn in a wireframe
and in a filled vector mode; at any time you can add, remove or modify
vertices, lines and surfaces, the system keeping track automatically of
your changes.
@{" The objects " LINK world_i_objects}
@{" Lines and surfaces " LINK world_i_lines}
@{" The coordinate system " LINK world_i_coords}
@endnode
@node world_i_objects "AFC module: Introduction / objects"
Two are the objects contained in this class: vectWorld and object_obj.
The latter represents a single 3D object containing its description in
terms of position of vertices, lines and/or surfaces. The former
represents the world in which to insert the objects before they are
rendered. You have to keep in mind this: objects can be manipulated and
drawn on the screen only when they are in a vectWorld, because it's the
vectWorld that contains notions as rotation, traslation, scaling and
observer position.
The methods are accordingly divided in two sets: one pertaining to the
vectWorld and one to the object_obj. Most of the methods of the two sets
share the same name, because they do exactly the same thing: the method of
vectWorld acts on objects already linked to that world, while the
corresponding method of object_obj acts on the single object.
But why this division can be useful? I must say that you're invited to
use only the methods of vectWorld (because otherwise, as I said before,
objects cannot be rendered), but perhaps you may want to keep your own
database of objects and link them to a vectWorld only when needed, and this
is where the methods of object_obj come into play.
@endnode
@node world_i_lines "AFC module: Introduction / lines and surfaces"
An object_obj contains vertices, lines and surfaces. No doubt you have
to define vertices before defining anything else, but you haven't to define
lines before surfaces: these two structures are independent but, anyway,
they aren't mutually exclusive. You need lines if you render the world in
wireframe; otherwise, if you use the filled vector mode you need only
surfaces.
@endnode
@node world_i_coords "AFC module: Introduction / coordinate system"
There's always a weird (for physicists) peculiarity in the coordinate
system of a computer world: unfortunately it's left-handed. The three
axes are directed as follows:
y
^ _ z
| /|
| /
| /
|/
|-----------> x
0
(obviuosly, negative coordinate values are allowed).
@endnode
@node Error_Table "AFC module: vectWorld / Error Table"
Val (Hex) | Description
-----------+------------------------------------------------------
$0000 | No Memory
$0001 | AreaInfo not available in init3D()
$0002 | TempRas not available in init3D()
$0003 | Vector buffer not available in init3D()
$0004 | Extra bitplane not available in init3D()
@endnode
*/
->///
OPT PREPROCESS
->#define WORLD_TEST
#ifndef WORLD_TEST
OPT MODULE
OPT EXPORT
#endif
MODULE 'dos/dos',
'exec/memory',
'exec/ports',
'graphics/gfx',
'graphics/rastport',
'graphics/gfxmacros',
'AFC/nodemaster'
#ifdef WORLD_TEST
MODULE 'intuition/intuition',
'intuition/screens',
'AFC/bitmapper',
'graphics/view'
#endif
->/// constants
CONST WORLD_NAMELEN=30, WORLD_BASE=$80050000
CONST WORLD_VERSION=1, WORLD_REVISION=0
-> exceptions
ENUM WORLD_ERR_MEM=WORLD_BASE, WORLD_ERR_AREAINFO, WORLD_ERR_TEMPRAS,
WORLD_ERR_VECTBUFFER, WORLD_ERR_BITPLANE
->///
-> /// 3D Objects
OBJECT screen_pixel -> a pixel (guess what are x AND y)
x
y
ENDOBJECT
OBJECT vertex_obj -> vertex structure
x
y
z
ENDOBJECT
OBJECT surface_vertex -> vertex linked TO a surface
PRIVATE
num:LONG -> only number (up TO now)
ENDOBJECT
OBJECT line_obj -> line structure:
startv -> start vertex
endv -> end vertex
colour -> line colour
ENDOBJECT
OBJECT surface_obj -> surface structure:
PRIVATE
vertex:PTR TO nodemaster -> LIST OF surface_vertex
colour -> colour
ENDOBJECT
OBJECT object_obj -> an OBJECT:
PRIVATE
vertex:PTR TO nodemaster -> LIST OF vertices
line:PTR TO nodemaster -> LIST OF lines
surface:PTR TO nodemaster -> LIST OF surfaces
name -> name
visible -> OBJECT visible?
proj:PTR TO nodemaster -> LIST OF projected vertices
tvert:PTR TO nodemaster -> LIST OF transformed vertices
pos_x -> origin OF local axes
pos_y
pos_z
scale_x -> local scaling factor
scale_y
scale_z
ENDOBJECT
OBJECT vectWorld -> the whole world
PRIVATE
numobj -> number OF objects
obj:PTR TO nodemaster -> LIST OF objects
rot_x -> rotation (degrees)
rot_y
rot_z
scale_x -> scale
scale_y
scale_z
trasl_x -> traslation
trasl_y
trasl_z
observer_x -> observer coords
observer_y
observer_z
scrtrasl_x -> traslation after projection
scrtrasl_y
scrscale_x -> scale after projection
scrscale_y
areai:PTR TO areainfo -> AreaInfo structure
tras:PTR TO tmpras -> TmpRas structure
buffer:PTR TO LONG -> buffer FOR AreaDraw
bplane:PTR TO LONG -> extra bitplane FOR AreaDraw
d_width -> display width (FOR bplane AND clipping)
d_height -> display height ( " " " " )
dw_old -> storage FOR old value OF d_width
dh_old -> " " " " " d_height
surflist:PTR TO nodemaster -> Z buffer (FOR surface sorting)
ENDOBJECT
-> ///
-> /// other DEFs AND PROCs
OBJECT stuff
PRIVATE
obj:PTR TO CHAR
surf
avg
ENDOBJECT
DEF sin_table:PTR TO LONG
PROC stuff() OF stuff
self.obj:=String(WORLD_NAMELEN)
IF self.obj=NIL THEN Raise(WORLD_ERR_MEM)
ENDPROC
PROC end() OF stuff
IF self.obj THEN DisposeLink(self.obj)
ENDPROC
#ifdef WORLD_TEST
PROC describe3DException()
IF exception
SELECT exception
CASE WORLD_ERR_MEM; WriteF('No Memory\n')
CASE WORLD_ERR_AREAINFO; WriteF('AreaInfo not available in init3D()\n')
CASE WORLD_ERR_TEMPRAS; WriteF('TempRas not available in init3D()\n')
CASE WORLD_ERR_VECTBUFFER; WriteF('Vector buffer not available in init3D()\n')
CASE WORLD_ERR_BITPLANE; WriteF('Extra bitplane not available in init3D()\n')
ENDSELECT
ENDIF
ENDPROC
PROC objectList(w:PTR TO vectWorld)
DEF o:PTR TO object_obj
IF (o:=w.obj.first())
REPEAT
WriteF('object_obj: \s\n',o.name)
UNTIL (o:=w.obj.succ())=FALSE
ENDIF
ENDPROC
PROC dumpObject(o:PTR TO object_obj)
DEF v:PTR TO vertex_obj, l:PTR TO line_obj
DEF s:PTR TO surface_obj, sv:PTR TO surface_vertex
WriteF('Name: \s\n',o.name)
IF (v:=o.vertex.first())
WriteF('*\n')
REPEAT
WriteF('\d vertex:\d - x:\d y:\d z:\d\n',v,o.vertex.numpos(),v.x,v.y,v.z)
UNTIL (v:=o.vertex.succ())=FALSE
ENDIF
IF (l:=o.line.first())
WriteF('$\n')
REPEAT
WriteF('\d line:\d - start:\d end:\d colour:\d\n',l,o.line.numpos(),l.startv,l.endv,l.colour)
UNTIL (l:=o.line.succ())=FALSE
ENDIF
IF (s:=o.surface.first())
WriteF('%\n')
REPEAT
WriteF('\d surface:\d - v: ',s,o.surface.numpos())
sv:=s.vertex.first()
REPEAT
WriteF('(\d)\d,',sv,sv.num)
UNTIL (sv:=s.vertex.succ())=FALSE
WriteF('\n')
UNTIL (s:=o.surface.succ())=FALSE
ENDIF
WriteF('#\n')
WriteF('pos_x:\d pos_y:\d pos_z:\d\n',o.pos_x,o.pos_y,o.pos_z)
WriteF('sc_x:\d sc_y:\d sc_z:\d\n', o.scale_x, o.scale_y, o.scale_z)
WriteF('visible:\s\n',IF o.visible THEN 'TRUE' ELSE 'FALSE')
ENDPROC
#endif
-> ///
-> /// surface functions
PROC surface_obj() OF surface_obj
NEW self.vertex.nodemaster()
ENDPROC
PROC end() OF surface_obj
DEF v:PTR TO surface_vertex
IF (v:=self.vertex.first())
REPEAT
END v
UNTIL (v:=self.vertex.succ())=FALSE
ENDIF
END self.vertex
ENDPROC
-> ///
-> OBJECT functions
->/// PROC object_obj(name=NIL) OF object_obj
/*
@node object_obj "AFC module: object_obj / object_obj()"
NAME: object_obj(name)
DESCRIPTION: creates an object_obj with name 'name'. The name
parameter is necessary because all objects in a vectWorld
are addressed with their names.
Objects cannot be rendered independently outside a world;
the object_obj methods are supplied to manipulate single
objects e.g. for storing purposes: you can, for example,
create a database of objects and then link to an
initialized vectWorld only the ones you actually need.
To link an already existing object to a vectWorld you use
the @{"vectWorld / setobj()" LINK world_setobj} method; alternatively you can
directly create and add an object to a world in one step by
calling the @{"vectWorld / addobj()" LINK world_addobj} method.
INPUTS: name of the object to be crated (max 30 chars).
RESULTS: NONE
SEE ALSO: @{" vectWorld / addobj() " LINK world_addobj}
@{" vectWorld / setobj() " LINK world_setobj}
@endnode
*/
PROC object_obj(name=NIL) OF object_obj
self.name:=String(WORLD_NAMELEN)
IF self.name
IF name
StrCopy(self.name,name)
ELSE
StrCopy(self.name,'No_Obj_Name')
ENDIF
ELSE
Raise(WORLD_ERR_MEM)
ENDIF
NEW self.vertex.nodemaster()
NEW self.line.nodemaster()
NEW self.proj.nodemaster()
NEW self.tvert.nodemaster()
NEW self.surface.nodemaster()
self.visible:=TRUE
self.pos_x:=0
self.pos_y:=0
self.pos_z:=0
self.scale_x:=100
self.scale_y:=100
self.scale_z:=100
ENDPROC
->///
->/// PROC clear() OF object_obj
/*
@node object_clear "AFC module: object_obj / clear()"
NAME: clear()
DESCRIPTION: clears all object's contents (except its name).
INPUTS: NONE
RESULTS: NONE
SEE ALSO: @{" vectWorld / clearobj() " LINK world_clearobj}
@endnode
*/
PROC clear() OF object_obj
DEF v:PTR TO vertex_obj
DEF l:PTR TO line_obj
DEF p:PTR TO screen_pixel
DEF s:PTR TO surface_obj
IF (v:=self.vertex.first())<>FALSE
REPEAT
END v
UNTIL (v:=self.vertex.succ())=FALSE
ENDIF
IF (l:=self.line.first())<>FALSE
REPEAT
END l
UNTIL (l:=self.line.succ())=FALSE
ENDIF
IF (p:=self.proj.first())<>FALSE
REPEAT
END p
UNTIL (p:=self.proj.succ())=FALSE
ENDIF
IF (v:=self.tvert.first())<>FALSE
REPEAT
END v
UNTIL (v:=self.tvert.succ())=FALSE
ENDIF
IF (s:=self.surface.first())<>FALSE
REPEAT
END s
UNTIL (s:=self.surface.succ())=FALSE
ENDIF
self.pos_x:=0
self.pos_y:=0
self.pos_z:=0
self.scale_x:=100
self.scale_y:=100
self.scale_z:=100
ENDPROC TRUE
->///
->/// PROC end() OF object_obj
PROC end() OF object_obj
self.clear()
END self.vertex
END self.line
END self.proj
END self.tvert
END self.surface
IF self.name THEN DisposeLink(self.name)
ENDPROC
->///
->/// PROC setvertex(num, x, y, z) OF object_obj
/*
@node object_setvertex "AFC module: object_obj / setvertex()"
NAME: setvertex(num, x, y, z)
DESCRIPTION: if 'num' is greater than the number of vertices of the
object, then a new vertex is added to the object at the
last position (independently of its number); so you cannot
leave holes e.g. by adding vertex 4 and then vertex 10:
in this case vertex 10 enters in position number 5.
This underlines one thing you have to care about:
vertices have NOT a fixed number; their number it's their
position in the list (for speed reasons). Usually the
module takes care of this automatically, but you must
remember it when you delete a vertex.
If 'num' is an already attached vertex, then this
instruction modifies the coordinates of that vertex.
Vertex numbers start from 0 (just like array elements).
INPUTS: num: number of the vertex
x, y, z: coordinates of the vertex.
RESULTS: FALSE if num<0, otherwise the number of vertices currently
in object.
SEE ALSO: @{" fastsetvert() " LINK object_fastsetvert}
@{" vectWorld / setvertex() " LINK world_setvertex}
@endnode
*/
PROC setvertex(num, x, y, z) OF object_obj
DEF v:PTR TO vertex_obj
DEF tv:PTR TO vertex_obj
IF num<0 THEN RETURN FALSE
IF num>(self.vertex.numitems()-1)
NEW v
v.x := x
v.y := y
v.z := z
self.vertex.add(v)
NEW tv
tv.x:=x
tv.y:=y
tv.z:=z
self.tvert.add(tv)
ELSE
v:=self.vertex.item(num)
v.x := x
v.y := y
v.z := z
tv:=self.tvert.item(num)
tv.x:=x
tv.y:=y
tv.z:=z
ENDIF
ENDPROC self.vertex.numitems()
->///
->/// PROC getvertex(num) OF object_obj
/*
@node object_getvertex "AFC module: object_obj / getvertex()"
NAME: getvertex(num)
DESCRIPTION: if num is a valid vertex number (that is to say in the
range [0 - ((number of vertices of the object)-1)]), this
call returns a pointer to a vertex_obj.
A vertex_obj contains three fields: x, y and z,
representing the three coordinates of the vertex. After
you got the pointer to a vertex_obj you can access its
coordinates by the usual way: vertex_obj.x, vertex_obj.y
and vertex_obj.z. I left this structure public because it
can be of some use for you.
INPUTS: number of (an existing) vertex; remember: vertex numbers
start from 0 (and go to (number of vertices in object)-1).
RESULTS: pointer to a vertex_obj
FALSE if num is an illegal number (e.g., num<0)
SEE ALSO: @{" setvertex() " LINK object_setvertex}
@{" vectWorld / getvertex() " LINK world_getvertex}
@endnode
*/
PROC getvertex(num) OF object_obj
IF (num>(self.vertex.numitems()-1)) OR (num<0) THEN RETURN FALSE
ENDPROC self.vertex.item(num)
->///
->/// PROC fastsetvert(vlist:PTR TO vertex_obj) OF object_obj
/*
@node object_fastsetvert "AFC module: object_obj / fastsetvert()"
NAME: fastsetvert(vertex_list)
DESCRIPTION: adds vertices to the object according to the content of
vertex_list. Vertex_list is a TYPED list of type
vertex_obj with the following form:
[x1,y1,z1, x2,y2,z2, ... ]:vertex_obj
This command is equivalent to the following code
FOR k:=0 to (number of vertices)-1
o.setvertex(k, x[k], y[k], z[k])
ENDFOR
but it's quicker.
INPUTS: vertex_list: list of vertices to be added.
RESULTS: NONE
SEE ALSO: @{" setvertex() " LINK object_setvertex}
@{" vectWorld / fastsetvert() " LINK world_fastsetvert}
@endnode
*/
PROC fastsetvert(vlist:PTR TO vertex_obj) OF object_obj
DEF v:PTR TO vertex_obj, tv:PTR TO vertex_obj
DEF k:REG
FOR k:=0 TO (ListLen(vlist)/3)-1
NEW v
v.x:=vlist[k].x
v.y:=vlist[k].y
v.z:=vlist[k].z
self.vertex.add(v)
NEW tv
v.x:=vlist[k].x
v.y:=vlist[k].y
v.z:=vlist[k].z
self.tvert.add(tv)
ENDFOR
ENDPROC TRUE
->///
->/// PROC delvertex(num) OF object_obj
/*
@node object_delvertex "AFC module: object_obj / delvertex()"
NAME: delvertex(num)
DESCRIPTION: removes a vertex from the object. Removes all references
to that vertex by deleting all lines and/or surfaces
attached to the vertex.
All vertex numbers will be scaled down one step to fill
in the hole leaved by the deletion.
INPUTS: number of vertex to be killed.
RESULTS: FALSE if num is not the number of an existing vertex (e.g.,
num<0), otherwise TRUE.
SEE ALSO: @{" setvertex() " LINK object_setvertex}
@{" vectWorld / delvertex() " LINK world_delvertex}
@endnode
*/
PROC delvertex(num) OF object_obj
DEF v:PTR TO vertex_obj, l:PTR TO line_obj
DEF s:PTR TO surface_obj, t:PTR TO surface_vertex
DEF flag
IF (num<0) OR (num>(self.vertex.numitems()-1)) THEN RETURN FALSE
v:=self.vertex.item(num)
END v
self.vertex.del()
v:=self.tvert.item(num)
END v
self.tvert.del()
IF (l:=self.line.first())
REPEAT
IF (l.startv=num) OR (l.endv=num)
END l
l:=self.line.del()
ELSE
IF l.startv>num THEN l.startv:=l.startv-1 -> i vertici non hanno
IF l.endv>num THEN l.endv:=l.endv-1 -> numeri assoluti e quindi
l:=self.line.succ() -> occorre riscalare tutto.
ENDIF
UNTIL l=FALSE
ENDIF
IF (s:=self.surface.first())
REPEAT
flag:=FALSE
IF (t:=s.vertex.first())
REPEAT
IF t.num=num THEN flag:=TRUE
IF t.num>num THEN t.num:=t.num-1 -> lo stesso qui.
UNTIL ((t:=s.vertex.succ())=FALSE) OR (flag=TRUE)
ENDIF
IF flag
END s
s:=self.surface.del()
ELSE
s:=self.surface.succ()
ENDIF
UNTIL s=FALSE
ENDIF
ENDPROC TRUE
->///
->/// PROC setline(num, sv, ev, colour) OF object_obj
/*
@node object_setline "AFC module: object_obj / setline()"
NAME: setline(num, startv, endv, colour)
DESCRIPTION: adds or modifies line number 'num' in object 'name': the
line starts from vertex number 'startv', ends in vertex
number 'endv' and has colour 'colour'.
If num is greater than the number of lines contained in
the object_obj, then the new line will be added as last
item; if num points to an existing line, then the new datas
will replace the old line definition.
This underlines one thing you have to care about:
lines have NOT a fixed number; their number it's their
position in the list (for speed reasons). Usually the
module takes care of this automatically, but you must
remember it when you delete a line.
Line numbers start from 0.
INPUTS: num: line number,
startv: starting line vertex,
endv: ending line vertex,
colour: line colour.
RESULTS: FALSE if num<0 or startv and/or endv outside the range of
existing vertices of the object,
otherwise the number of lines currently in object.
SEE ALSO: @{" vectWorld / setline() " LINK world_setline}
@endnode
*/
PROC setline(num, sv, ev, colour) OF object_obj
DEF l:PTR TO line_obj
IF (sv>(self.vertex.numitems()-1)) OR (sv<0) THEN RETURN FALSE
IF (ev>(self.vertex.numitems()-1)) OR (ev<0) THEN RETURN FALSE
IF num<0 THEN RETURN FALSE
IF num>(self.line.numitems()-1)
NEW l
l.startv := sv
l.endv := ev
l.colour := colour
self.line.add(l)
ELSE
l:=self.line.item(num)
l.startv := sv
l.endv := ev
l.colour := colour
ENDIF
ENDPROC self.line.numitems()
->///
->/// PROC getline(num) OF object_obj
/*
@node object_getline "AFC module: object_obj / getline()"
NAME: getline(num)
DESCRIPTION: returns a description of line number 'num' in the form of a
pointer to a line_obj. An object of type line_obj contains
three fields named 'startv', 'endv' and 'colour'; after
having received the pointer you access those fields in the
usual way: line_obj.startv, line_obj.endv and
line_obj.colour.
I left the line_obj object description public because it
can be of use to you.
INPUTS: number of line to be inquired.
RESULTS: FALSE if num is outside the valid range of existing line
numbers (going from 0 to (number of lines)-1),
otherwise a pointer to a line_obj.
SEE ALSO: @{" setline() " LINK object_setline}
@{" vectWorld / getline() " LINK world_getline}
@endnode
*/
PROC getline(num) OF object_obj
IF (num>(self.line.numitems()-1)) OR (num<0) THEN RETURN FALSE
ENDPROC self.line.item(num)
->///
->/// PROC fastsetline(llist:PTR TO line_obj) OF object_obj
/*
@node object_fastsetline "AFC module: object_obj / fastsetline()"
NAME: fastsetline(line_list)
DESCRIPTION: adds the line descriptions contained in line_list to the
object. Line_list is a TYPED list of type line_obj of the
following form:
[startv1,endv1,colour1, startv2,endv2,colour2, ...]:line_obj
This command is equivalent to the following code
FOR k:=0 to (number of lines)-1
o.setline(k, startv[k], endv[k], colour[k])
ENDFOR
but it's quicker.
If a startv or endv exceeds the range of existing vertex
numbers for the object, then it is automatically set to
vertex number 0.
INPUTS: list of lines to be added.
RESULTS: NONE
SEE ALSO: @{" setline() " LINK object_setline}
@{" vectWorld / fastsetline() " LINK world_fastsetline}
@endnode
*/
PROC fastsetline(llist:PTR TO line_obj) OF object_obj
DEF l:PTR TO line_obj
DEF k:REG, sv,ev
FOR k:=0 TO (ListLen(llist)/3)-1
sv:=llist[k].startv
ev:=llist[k].endv
IF (sv>(self.vertex.numitems()-1)) OR (sv<0) THEN sv:=0
IF (ev>(self.vertex.numitems()-1)) OR (ev<0) THEN ev:=0
NEW l
l.startv := sv
l.endv := ev
l.colour := llist[k].colour
self.line.add(l)
ENDFOR
ENDPROC TRUE
->///
->/// PROC delline(num) OF object_obj
/*
@node object_delline "AFC module: object_obj / delline()"
NAME: delline(num)
DESCRIPTION: removes line number 'num' from the object.
All line numbers will be scaled down one step to fill in
the hole leaved by the deletion.
INPUTS: number of line to be killed.
RESULTS: FALSE if num is outside the valid range for the object.
SEE ALSO: @{" setline() " LINK object_setline}
@{" vectWorld / delline() " LINK world_delline}
@endnode
*/
PROC delline(num) OF object_obj
DEF l:PTR TO line_obj
IF (num<0) OR (num>(self.line.numitems()-1)) THEN RETURN FALSE
l:=self.line.item(num)
END l
self.line.del()
ENDPROC TRUE
->///
->/// PROC setsurface(num,vlist:PTR TO LONG,col) OF object_obj
/*
@node object_setsurface "AFC module: object_obj / setsurface()"
NAME: setsurface(num, vertex_list, colour)
DESCRIPTION: adds (or modifies) a surface. If num is greater than the
number of surfaces contained in the object, then the new
surface will be added at the end of the list; if num points
to an existing surface, then the contents of that surface
will be replaced by the new datas.
The vertex_list is a list of vertex NUMBERS belonging to
the surface, in the following order: you rotate the object
until the surface is visible and then enumerate the
vertices in a clockwise direction.
I want to underline one thing you have to care about:
surfaces have NOT a fixed number; their number it's their
position in the list (for speed reasons). Usually the
module takes care of this automatically, but you must
remember it when you delete a surface.
Surface numbers start from 0.
If a vertex number in the list is outside the range of
existing vertices, then it is arbitrarily set to vertex
number 0.
If you modify a surface it doesn't matter if the new
vertex_list is shorter or longer than the previous one.
INPUTS: num: number of surface,
vertex_list: list of vertex numbers,
colour: surface colour register.
RESULTS: FALSE if num<0,
otherwise the total number of surfaces in the object.
SEE ALSO: @{" vectWorld / setsurface() " LINK world_setsurface}
@endnode
*/
PROC setsurface(num,vlist:PTR TO LONG,col) OF object_obj
DEF s:PTR TO surface_obj, mode=0
DEF k:REG, t, v:PTR TO surface_vertex
IF num<0 THEN RETURN FALSE
IF num>(self.surface.numitems()-1)
NEW s.surface_obj()
FOR k:=0 TO ListLen(vlist)-1
t:=vlist[k]
IF (t<0) OR (t>(self.vertex.numitems()-1)) THEN t:=0
NEW v
v.num:=t
s.vertex.add(v)
ENDFOR
s.colour:=col
self.surface.add(s)
ELSE
s:=self.surface.item(num)
IF s.vertex.numitems()>0
v:=s.vertex.first()
mode:=0 -> replace
ELSE
mode:=1 -> add
ENDIF
k:=0
REPEAT
t:=vlist[k]
IF (t<0) OR (t>(self.vertex.numitems()-1)) THEN t:=0
IF mode=1 THEN NEW v
v.num:=t
k:=k+1
IF mode=1
s.vertex.add(v)
ELSE
v:=s.vertex.succ()
IF v=FALSE THEN mode:=1 -> switch TO add
ENDIF
UNTIL k>=ListLen(vlist)
IF mode=0 -> remove tail
FOR k:=s.vertex.numpos() TO s.vertex.numitems()-1
END v
v:=s.vertex.del()
ENDFOR
ENDIF
s.colour:=col
ENDIF
ENDPROC self.surface.numitems()
->///
->/// PROC getsurface(num,vnum) OF object_obj
/*
@node object_getsurface "AFC module: object_obj / getsurface()"
NAME: getsurface(snum, vnum)
DESCRIPTION: returns the vertex number contained in position vnum of
surface snum.
INPUTS: snum: number of surface to be inquired,
vnum: position of vertex in the surface's list.
RESULTS: vertex number contained in position vnum,
FALSE if snum outside the valid range or vnum outside the
valid range for the object.
SEE ALSO: @{" setsurface() " LINK object_setsurface}
@{" vectWorld / getsurface() " LINK world_getsurface}
@endnode
*/
PROC getsurface(num,vnum) OF object_obj
DEF s:PTR TO surface_obj
DEF v:PTR TO surface_vertex
IF (num<0) OR (num>(self.surface.numitems()-1)) THEN RETURN FALSE
s:=self.surface.item(num)
IF (vnum>=0) AND (vnum<=(s.vertex.numitems()-1))
v:=s.vertex.item(vnum)
ELSE
RETURN FALSE
ENDIF
ENDPROC v.num
->///
->/// PROC delsurface(num) OF object_obj
/*
@node object_delsurface "AFC module: object_obj / delsurface()"
NAME: delsurface(num)
DESCRIPTION: removes surface number 'num' from the object. All surface
numbers will be scaled down by one step to fill in the hole
leaved by the deletion.
INPUTS: number of the surface to be killed.
RESULTS: FALSE if num is outside the valid range for the object,
otherwise TRUE.
SEE ALSO: @{" setsurface() " LINK object_setsurface}
@{" vectWorld / delsurface() " LINK world_delsurface}
@endnode
*/
PROC delsurface(num) OF object_obj
DEF s:PTR TO surface_obj
IF (num<0) OR (num>(self.surface.numitems()-1)) THEN RETURN FALSE
s:=self.surface.item(num)
END s
self.surface.del()
ENDPROC TRUE
->///
->/// PROC projection(obs_x,obs_y,obs_z) OF object_obj
/*
@node object_projection "AFC module: object_obj / projection()"
NAME: projection(x, y, z)
DESCRIPTION: reduces the 3D coordinates of the object in a 2D
representation, according to the position of the observer
(specified with the x, y and z parameters). Local axes are
not supplied, so you cannot rotate objects individually;
besides, you cannot draw objects individually. To perform
rotations and drawing you have to link the object to a
vectWorld.
INPUTS: position of the observer.
RESULTS: NONE
SEE ALSO: @{" vectWorld / projection() " LINK world_projection}
@endnode
*/
PROC projection(obs_x,obs_y,obs_z) OF object_obj
DEF p_x,p_y, den
DEF p:PTR TO screen_pixel
DEF v:PTR TO vertex_obj
DEF b=90, mode=0
IF (v:=self.tvert.first())<>FALSE
IF (p:=self.proj.first())<>FALSE THEN mode:=1 ->recycle
REPEAT
den:=v.z-obs_z
IF den<=0 THEN den:=1
p_x:=Div(Mul(b,v.x-obs_x),den)
p_y:=Div(Mul(b,v.y-obs_y),den)
IF mode=0 THEN NEW p
p.x:=p_x
p.y:=p_y
IF mode=1
IF (p:=self.proj.succ())=FALSE THEN mode:=0 ->switch TO add
ELSE
self.proj.add(p)
ENDIF
UNTIL (v:=self.tvert.succ())=FALSE
ENDIF
ENDPROC TRUE
->///
->/// PROC getpoint(vertex) OF object_obj
/*
@node object_getpoint "AFC module: object_obj / getpoint()"
NAME: getpoint(vertex)
DESCRIPTION: returns the coordinates of a projected vertex in the form
of a pointer to a screen_pixel object. Such an object is
made of two fields named 'x' and 'y' (guess what they
mean!); after having got the pointer you access the two
coordinates by the usual way: screen_pixel.x,
screen_pixel.y.
INPUTS: number of the vertex to be inquired.
RESULTS: pointer to a screen_pixel object,
FALSE if vertex is outside the valid range for the object.
SEE ALSO: @{" projection() " LINK object_projection}
@{" vectWorld / getpoint() " LINK world_getpoint}
@endnode
*/
PROC getpoint(vertex) OF object_obj
DEF p:PTR TO screen_pixel
IF (vertex>(self.proj.numitems()-1)) OR (vertex<0) THEN RETURN FALSE
p:=self.proj.item(vertex)
ENDPROC p.x, p.y
->///
->/// PROC draw(rp) OF object_obj
PROC draw(rp) OF object_obj
DEF p1:PTR TO screen_pixel
DEF p2:PTR TO screen_pixel
DEF l:PTR TO line_obj
IF (l:=self.line.first())<>FALSE
REPEAT
IF (p1:=self.proj.item(l.startv))<>FALSE
IF (p2:=self.proj.item(l.endv))<>FALSE
SetAPen(rp, l.colour)
Move(rp, p1.x, p1.y)
Draw(rp, p2.x, p2.y)
ENDIF
ENDIF
UNTIL (l:=self.line.succ())=FALSE
ELSEIF (p1:=self.proj.first())<>FALSE
REPEAT
WritePixel(rp,p1.x,p1.y)
UNTIL (p1:=self.proj.succ())=FALSE
ENDIF
ENDPROC
->///
->/// PROC visible(v=-10) OF object_obj
PROC visible(v=-10) OF object_obj
IF v=-10 THEN RETURN self.visible
self.visible:=IF v THEN TRUE ELSE FALSE
ENDPROC TRUE
->///
->/// PROC position(x,y,z) OF object_obj
/*
@node object_position "AFC module: object_obj / position()"
NAME: position(x, y, z)
DESCRIPTION: moves the origin of the object's local axes to the
position specified. This means you can always enter the
object's coordinates relative to the object's local origin
and then move the object around in the vectWorld.
This method only sets the origin coordinates to the new
values, and the traslation is performed every time the
object is @{"project()" LINK world_projection}ed within a vectWorld: this behaviour
obviuosly slows down the projection routine. If you want
to make the changes permanent (calculated once for ever)
you call the @{"apply()" LINK object_apply} method.
To traslate the whole vectWorld you can use the
@{"settrasl()" LINK world_settrasl} method.
INPUTS: coordinates of the local origin.
RESULTS: NONE
SEE ALSO: @{" apply() " LINK object_apply}
@{" vectWorld / position() " LINK world_position}
@endnode
*/
PROC position(x,y,z) OF object_obj
self.pos_x:=x
self.pos_y:=y
self.pos_z:=z
ENDPROC TRUE
->///
->/// PROC scale(x,y,z) OF object_obj
/*
@node object_scale "AFC module: object_obj / scale()"
NAME: scale(x, y, z)
DESCRIPTION: scales the object.
This method only sets the scaling factors to the new
values, and the scaling is performed every time the object
is @{"project()" LINK world_projection}ed within a vectWorld: this behaviour
obviuosly slows down the projection routine. If you want
to make the changes permanent (calculated once for ever)
you call the @{"apply()" LINK object_apply} method.
The scaling factors are entered as a percentage: 100
means original dimensions, 50 means a half, and so on...
To scale the whole vectWorld you can use the
@{"setscale()" LINK world_setscale} method.
INPUTS: scaling factors.
RESULTS: NONE
SEE ALSO: @{" apply() " LINK object_apply}
@{" vectWorld / scale() " LINK world_scale}
@endnode
*/
PROC scale(x,y,z) OF object_obj
IF x<=0 THEN x:=100
IF y<=0 THEN y:=100
IF z<=0 THEN z:=100
self.scale_x:=x
self.scale_y:=y
self.scale_z:=z
ENDPROC TRUE
->///
->/// PROC copy(dest:PTR TO object_obj) OF object_obj
/*
@node object_copy "AFC module: object_obj / copy()"
NAME: copy(dest:PTR TO object_obj)
DESCRIPTION: copies all the contents of an object (except its name) to
the destination object: the latter will be @{"clear()" LINK object_clear}ed
before being modified.
INPUTS: pointer to an already initialized object_obj.
RESULTS: FALSE if dest=NIL, otherwise TRUE.
It may raise exceptions (see the @{"Error Table" LINK Error_Table}).
SEE ALSO: @{" clone() " LINK object_clone}
@{" vectWorld / copyobj() " LINK world_copyobj}
@endnode
*/
PROC copy(dest:PTR TO object_obj) OF object_obj
DEF fv:PTR TO vertex_obj, dv:PTR TO vertex_obj
DEF fl:PTR TO line_obj, dl:PTR TO line_obj
DEF fs:PTR TO surface_obj, ds:PTR TO surface_obj
DEF fsv:PTR TO surface_vertex, dsv:PTR TO surface_vertex
IF (dest=NIL) THEN RETURN FALSE
dest.clear()
IF (fv:=self.vertex.first())
REPEAT
NEW dv
dv.x:=fv.x
dv.y:=fv.y
dv.z:=fv.z
dest.vertex.add(dv)
NEW dv
dv.x:=fv.x
dv.y:=fv.y
dv.z:=fv.z
dest.tvert.add(dv)
UNTIL (fv:=self.vertex.succ())=FALSE
ENDIF
IF (fl:=self.line.first())<>FALSE
REPEAT
NEW dl
dl.startv:=fl.startv
dl.endv:=fl.endv
dl.colour:=fl.colour
dest.line.add(dl)
UNTIL (fl:=self.line.succ())=FALSE
ENDIF
IF (fs:=self.surface.first())<>FALSE
REPEAT
NEW ds.surface_obj()
IF (fsv:=fs.vertex.first())
REPEAT
NEW dsv
dsv.num:=fsv.num
ds.vertex.add(dsv)
UNTIL (fsv:=fs.vertex.succ())=FALSE
ENDIF
ds.colour:=fs.colour
dest.surface.add(ds)
UNTIL (fs:=self.surface.succ())=FALSE
ENDIF
dest.visible:=self.visible
dest.pos_x:=self.pos_x
dest.pos_y:=self.pos_y
dest.pos_z:=self.pos_z
dest.scale_x:=self.scale_x
dest.scale_y:=self.scale_y
dest.scale_z:=self.scale_z
ENDPROC TRUE
->///
->/// PROC clone(name=NIL) OF object_obj
/*
@node object_clone "AFC module: object_obj / clone()"
NAME: clone(newname=NIL)
DESCRIPTION: creates a new object_obj and copies the contents of the
current object to the new one. The newname parameter will
be the name of the newborn object_obj (if it is not
supplied the new name will be something like
'Copy_of_oldname').
INPUTS: name of the object to be created.
RESULTS: pointer to the new object_obj.
SEE ALSO: @{" copy() " LINK object_copy}
@{" vectWorld / cloneobj() " LINK world_cloneobj}
@endnode
*/
PROC clone(name=NIL) OF object_obj
DEF dest=NIL:PTR TO object_obj, s[WORLD_NAMELEN]:STRING
IF name
StrCopy(s, name)
ELSE
StringF(s, 'Copy_of_\s', self.name)
ENDIF
NEW dest.object_obj(s)
self.copy(dest)
ENDPROC dest
->///
->/// PROC name() OF object_obj
/*
@node object_name "AFC module: object_obj / name()"
NAME: name()
DESCRIPTION: returns the object's name.
INPUTS: NONE
RESULTS: object's name.
SEE ALSO:
@endnode
*/
PROC name() OF object_obj IS self.name
->///
->/// PROC apply() OF object_obj
/*
@node object_apply "AFC module: object_obj / apply()"
NAME: apply()
DESCRIPTION: makes the changes on an object permanent (calculated once
for ever). Changes such as @{"position()" LINK object_position} or @{"scale()" LINK object_scale} of an
object_obj are affected: this increases the speed of the
@{"projection()" LINK world_projection} routine, because permanent transformations
are skipped.
INPUTS: NONE
RESULTS: NONE
SEE ALSO: @{" position() " LINK object_position}
@{" scale() " LINK object_scale}
@{" vectWorld / applyobj() " LINK world_applyobj}
@endnode
*/
PROC apply() OF object_obj
DEF v:PTR TO vertex_obj
IF (v:=self.vertex.first())
IF (self.pos_x<>0) OR (self.pos_y<>0) OR (self.pos_z<>0)
REPEAT
IF (self.pos_x<>0) THEN v.x:=v.x+self.pos_x
IF (self.pos_y<>0) THEN v.y:=v.y+self.pos_y
IF (self.pos_z<>0) THEN v.z:=v.z+self.pos_z
UNTIL (v:=self.vertex.succ())=FALSE
ENDIF
IF (self.scale_x<>100) OR (self.scale_y<>100) OR (self.scale_z<>100)
v:=self.vertex.first()
REPEAT
IF (self.scale_x<>100) THEN v.x:=Div(Mul(v.x,self.scale_x),100)
IF (self.scale_y<>100) THEN v.y:=Div(Mul(v.y,self.scale_y),100)
IF (self.scale_z<>100) THEN v.z:=Div(Mul(v.z,self.scale_z),100)
UNTIL (v:=self.vertex.succ())=FALSE
ENDIF
self.pos_x:=0
self.pos_y:=0
self.pos_z:=0
self.scale_x:=100
self.scale_y:=100
self.scale_z:=100
ENDIF
ENDPROC TRUE
-> ///
-> World Functions
->/// PROC vectWorld() OF vectWorld
/*
@node vectWorld "AFC module: vectWorld / vectWorld()"
NAME: vectWorld()
DESCRIPTION: builds a vectWorld object (constructor).
INPUTS: NONE
RESULTS: NONE
SEE ALSO:
@endnode
*/
PROC vectWorld() OF vectWorld
NEW self.obj.nodemaster()
self.rot_x:=0
self.rot_y:=0
self.rot_z:=0
self.scale_x:=100
self.scale_y:=100
self.scale_z:=100
self.trasl_x:=0
self.trasl_y:=0
self.trasl_z:=0
self.scrscale_x:=100
self.scrscale_y:=100
self.scrtrasl_x:=0
self.scrtrasl_y:=0
self.observer_x:=0
self.observer_y:=0
self.observer_z:=-1
self.d_width:=320
self.d_height:=256
IF sin_table=NIL THEN fillSinTable()
ENDPROC
->///
->/// PROC end() OF vectWorld
PROC end() OF vectWorld
DEF o:PTR TO object_obj
DEF g:PTR TO stuff
IF (o:=self.obj.first())<>FALSE
REPEAT
END o
UNTIL (o:=self.obj.succ())=FALSE
ENDIF
END self.obj
IF self.areai THEN END self.areai
IF self.tras THEN END self.tras
IF self.buffer THEN FreeVec(self.buffer)
IF self.bplane THEN FreeRaster(self.bplane,self.d_width,self.d_height)
IF self.surflist<>NIL
IF (g:=self.surflist.first())<>FALSE
REPEAT
END g
UNTIL (g:=self.surflist.succ())=FALSE
ENDIF
END self.surflist
ENDIF
ENDPROC
->///
->/// PROC addobj(name) OF vectWorld
/*
@node world_addobj "AFC module: vectWorld / addobj()"
NAME: addobj(name)
DESCRIPTION: creates an object_obj called 'name' and adds it to the
vectWorld. The name parameter is necessary because all
objects in a world are recognized by their names.
INPUTS: the name of the object to be created (max 30 chars).
RESULTS: NONE
SEE ALSO: @{" object_obj() " LINK object_obj}
@{" setobj() " LINK world_setobj}
@endnode
*/
PROC addobj(name) OF vectWorld
DEF o:PTR TO object_obj
NEW o.object_obj(name)
self.obj.add(o)
ENDPROC
->///
->/// PROC setobj(o) OF vectWorld
/*
@node world_setobj "AFC module: vectWorld / setobj()"
NAME: setobj(object)
DESCRIPTION: links an existing object_obj to the vectWorld.
INPUTS: 'object' is the pointer to an object_obj.
RESULTS: NONE
SEE ALSO: @{" addobj() " LINK world_addobj}
@{" getobj() " LINK world_getobj}
@endnode
*/
PROC setobj(o) OF vectWorld
IF o THEN self.obj.add(o)
ENDPROC
->///
->/// PROC getobj(name) OF vectWorld
/*
@node world_getobj "AFC module: vectWorld / getobj()"
NAME: getobj(name)
DESCRIPTION: returns the pointer to the object_obj named 'name'.
INPUTS: name of the object.
RESULTS: pointer to an object_obj.
SEE ALSO: @{" setobj() " LINK world_setobj}
@{" addobj() " LINK world_addobj}
@endnode
*/
PROC getobj(name) OF vectWorld
DEF o
IF (o:=self.posonobj(name))<>FALSE THEN RETURN o
ENDPROC FALSE
->///
->/// PROC delobj(name) OF vectWorld
/*
@node world_delobj "AFC module: vectWorld / delobj()"
NAME: delobj(name)
DESCRIPTION: unlinks from the vectWorld and deletes (freeing all memory
associated with it) the object 'name'. If such an object
doesn't exist, it does nothing.
INPUTS: name of the object to be killed.
RESULTS: NONE
SEE ALSO: @{" addobj() " LINK world_addobj}
@{" unlinkobj() " LINK world_unlinkobj}
@endnode
*/
PROC delobj(name) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))<>FALSE
END o
self.obj.del()
ENDIF
ENDPROC
->///
->/// PROC unlinkobj(name) OF vectWorld
/*
@node world_unlinkobj "AFC module: vectWorld / unlinkobj()"
NAME: unlinkobj(name)
DESCRIPTION: removes the object 'name' from the vectWorld, without
freeing its memory. It returns a pointer to an object_obj,
that you must remember to END yourself before exiting the
program.
INPUTS: name of the object to unlink.
RESULTS: pointer to an object_obj, or FALSE if 'name' not found.
SEE ALSO: @{" delobj() " LINK world_delobj}
@endnode
*/
PROC unlinkobj(name) OF vectWorld
DEF o
IF (o:=self.posonobj(name))
self.obj.del()
RETURN o
ENDIF
ENDPROC FALSE
->///
->/// PROC posonobj(name) OF vectWorld
PROC posonobj(name) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.obj.obj())<>NIL
IF StrCmp(o.name,name)=FALSE
o:=self.obj.first()
REPEAT
IF StrCmp(o.name,name)=TRUE THEN RETURN o
UNTIL (o:=self.obj.succ())=FALSE
RETURN FALSE
ELSE
RETURN o
ENDIF
ENDIF
ENDPROC
->///
->/// PROC setvertex(name, num, x, y, z) OF vectWorld
/*
@node world_setvertex "AFC module: vectWorld / setvertex()"
NAME: setvertex(name, num, x, y, z)
DESCRIPTION: same as @{"object_obj / setvertex()" LINK object_setvertex}
INPUTS: name of the object_obj to be modified
num: vertex number
x, y, z: vertex coordinates
RESULTS: FALSE if object not found,
otherwise the number of vertices currently in object.
SEE ALSO: @{" fastsetvert() " LINK world_fastsetvert}
@{" object_obj / setvertex() " LINK object_setvertex}
@endnode
*/
PROC setvertex(name, num, x, y, z) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.setvertex(num, x, y, z)
->///
->/// PROC getvertex(name, num) OF vectWorld
/*
@node world_getvertex "AFC module: vectWorld / getvertex()"
NAME: getvertex(name, num)
DESCRIPTION: same as @{"object_obj / getvertex()" LINK object_getvertex}
INPUTS: name of the object to be inquired
num: number of vertex
RESULTS: FALSE if object not found, or num outside a valid range,
pointer to vertex_obj if successful.
SEE ALSO: @{" setvertex() " LINK world_setvertex}
@{" object_obj / getvertex() " LINK object_getvertex}
@endnode
*/
PROC getvertex(name, num) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.getvertex(num)
->///
->/// PROC fastsetvert(name,vlist:PTR TO vertex_obj) OF vectWorld
/*
@node world_fastsetvert "AFC module: vectWorld / fastsetvert()"
NAME: fastsetvert(name, vertex_list)
DESCRIPTION: same as @{"object_obj / fastsetvert()" LINK object_fastsetvert}
INPUTS: name of the object to be modified
vertex_list of vertices to be added.
RESULTS: FALSE if object not found.
SEE ALSO: @{" setvertex() " LINK world_setvertex}
@{" object_obj / fastsetvert() " LINK object_fastsetvert}
@endnode
*/
PROC fastsetvert(name,vlist:PTR TO vertex_obj) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.fastsetvert(vlist)
->///
->/// PROC delvertex(name,num) OF vectWorld
/*
@node world_delvertex "AFC module: vectWorld / delvertex()"
NAME: delvertex(name, num)
DESCRIPTION: same as @{"object_obj / delvertex()" LINK object_delvertex}
INPUTS: name of the object to be modified
num: number of vertex to be killed.
RESULTS: FALSE if object not found, or num outside a valid range,
otherwise TRUE.
SEE ALSO: @{" setvertex() " LINK world_setvertex}
@{" object_obj / delvertex() " LINK object_delvertex}
@endnode
*/
PROC delvertex(name,num) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.delvertex(num)
->///
->/// PROC setline(name, numline, sv, ev, colour) OF vectWorld
/*
@node world_setline "AFC module: vectWorld / setline()"
NAME: setline(name, num, startv, endv, colour)
DESCRIPTION: same as @{"object_obj / setline()" LINK object_setline}
INPUTS: name of the object to be modified,
num: number of line,
startv: line starting vertex,
endv: line ending vertex,
colour: line colour register.
RESULTS: FALSE if object not found,
FALSE if num<0 or startv and/or endv outside the range of
existing vertices of the object,
otherwise the number of lines currently in the object.
SEE ALSO: @{" fastsetline() " LINK world_fastsetline}
@{" object_obj / setline() " LINK object_setline}
@endnode
*/
PROC setline(name, numline, sv, ev, colour) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.setline(numline, sv, ev, colour)
->///
->/// PROC getline(name, numline) OF vectWorld
/*
@node world_getline "AFC module: vectWorld / getline()"
NAME: getline(name, num)
DESCRIPTION: same as @{"object_obj / getline()" LINK object_getline}
INPUTS: name of the object,
num: line number.
RESULTS: FALSE if object not found, or num outside the range of
existing line numbers.
SEE ALSO: @{" setline() " LINK world_setline}
@{" object_obj / getline() " LINK object_getline}
@endnode
*/
PROC getline(name, numline) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.getline(numline)
->///
->/// PROC fastsetline(name, llist:PTR TO line_obj) OF vectWorld
/*
@node world_fastsetline "AFC module: vectWorld / fastsetline()"
NAME: fastsetline(name, line_list)
DESCRIPTION: same as @{"object_obj / fastsetline()" LINK object_fastsetline}
INPUTS: name of the object to be modified,
line_list: typed list of objects line_obj.
RESULTS: FALSE if object not found, otherwise TRUE
SEE ALSO: @{" setline() " LINK world_setline}
@{" object_obj / fastsetline() " LINK object_fastsetline}
@endnode
*/
PROC fastsetline(name, llist:PTR TO line_obj) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.fastsetline(llist)
->///
->/// PROC delline(name,num) OF vectWorld
/*
@node world_delline "AFC module: vectWorld / delline()"
NAME: delline(name, num)
DESCRIPTION: same as @{"object_obj / delline()" LINK object_delline}
INPUTS: name of the object to be modified,
num: number of line to be killed.
RESULTS: FALSE if object not found, or num outside the valid line
numbers range for the object.
SEE ALSO: @{" setline() " LINK world_setline}
@{" object_obj / delline() " LINK object_delline}
@endnode
*/
PROC delline(name,num) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.delline(num)
->///
->/// PROC setsurface(name,num,vlist:PTR TO LONG,col) OF vectWorld
/*
@node world_setsurface "AFC module: vectWorld / setsurface()"
NAME: setsurface(name, num, vertex_list, colour)
DESCRIPTION: same as @{"object_obj / setsurface()" LINK object_setsurface}
INPUTS: name of the object to be modified,
num: number of surface,
vertex_list: list of vertex numbers defining the surface,
colour: surface colour register.
RESULTS: FALSE if object not found, or num<0
SEE ALSO: @{" object_obj / setsurface() " LINK object_setsurface}
@endnode
*/
PROC setsurface(name,num,vlist:PTR TO LONG,col) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.setsurface(num,vlist,col)
->///
->/// PROC getsurface(name,num,vnum) OF vectWorld
/*
@node world_getsurface "AFC module: vectWorld / getsurface()"
NAME: getsurface(name, snum, vnum)
DESCRIPTION: same as @{"object_obj / getsurface()" LINK object_getsurface}
INPUTS: name of the object,
snum: number of surface to be inquired,
vnum: number of vertex
RESULTS: FALSE if object not found or snum outside the valid range
or vnum outside the valid range for the object,
otherwise the vertex number in position vnum.
SEE ALSO: @{" setsurface() " LINK world_setsurface}
@{" object_obj / getsurface() " LINK object_getsurface}
@endnode
*/
PROC getsurface(name,num,vnum) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.getsurface(num,vnum)
->///
->/// PROC delsurface(name,num) OF vectWorld
/*
@node world_delsurface "AFC module: vectWorld / delsurface()"
NAME: delsurface(name, num)
DESCRIPTION: same as @{"object_obj / delsurface()" LINK object_delsurface}
INPUTS: name of the object to be modified,
num: number of surface to be killed.
RESULTS: FALSE if object not found or num outside the valid surface
number range for the object,
otherwise TRUE.
SEE ALSO: @{" setsurface() " LINK world_setsurface}
@{" object_obj / delsurface() " LINK object_delsurface}
@endnode
*/
PROC delsurface(name,num) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.delsurface(num)
->///
->/// PROC getpoint(name,v) OF vectWorld
/*
@node world_getpoint "AFC module: vectWorld / getpoint()"
NAME: getpoint(name, vertex)
DESCRIPTION: same as @{"object_obj / getpoint()" LINK object_getpoint}
INPUTS: name of the object,
vertex number to be inquired.
RESULTS: FALSE if object not found or vertex number outside the
valid range for the object,
otherwise the pointer to a screen_pixel object.
SEE ALSO: @{" object_obj / getpoint() " LINK object_getpoint}
@endnode
*/
PROC getpoint(name,v) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.getpoint(v)
->///
->/// PROC visible(name,v=-10) OF vectWorld
/*
@node world_visible "AFC module: vectWorld / visible()"
NAME: visible(name [,v])
DESCRIPTION: an object is by default visible, that is to say it will be
drawn on the scene. If v=FALSE then the object won't
appear on the scene any more, until v is reset to TRUE. If
v is omitted then the function returns the state of the
object.
INPUTS: name of the object to be modified,
v: TRUE if visible, FALSE if not
RESULTS: FALSE if object not found, otherwise TRUE; if v is omitted
then the result is the state of the object.
SEE ALSO:
@endnode
*/
PROC visible(name,v=-10) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.visible(v)
->///
->/// PROC position(name, x,y,z) OF vectWorld
/*
@node world_position "AFC module: vectWorld / position()"
NAME: position(name, x,y,z)
DESCRIPTION: same as @{"object_obj / position()" LINK object_position}.
INPUTS: name of the object ot be modified,
coordinates of the local origin.
RESULTS: FALSE if object not found.
SEE ALSO: @{" applyobj() " LINK world_applyobj}
@{" object_obj / position() " LINK object_position}
@endnode
*/
PROC position(name, x,y,z) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.position(x,y,z)
->///
->/// PROC scale(name, x,y,z) OF vectWorld
/*
@node world_scale "AFC module: vectWorld / scale()"
NAME: scale(name, x,y,z)
DESCRIPTION: same as @{"object_obj / scale()" LINK object_scale}.
INPUTS: name of the object to be modified,
scaling factors.
RESULTS: FALSE if object not found.
SEE ALSO: @{" applyobj() " LINK world_applyobj}
@{" object_obj / scale() " LINK object_scale}
@endnode
*/
PROC scale(name, x,y,z) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.scale(x,y,z)
->///
->/// PROC clearobj(name) OF vectWorld
/*
@node world_clearobj "AFC module: vectWorld / clearobj()"
NAME: clearobj(name)
DESCRIPTION: same as @{"object_obj / clear()" LINK object_clear}.
INPUTS: name of the object to be cleared.
RESULTS: FALSE if object not found, otherwise TRUE.
SEE ALSO: @{" object_obj / clear() " LINK object_clear}
@endnode
*/
PROC clearobj(name) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.clear()
->///
->/// PROC copyobj(fname, dname) OF vectWorld
/*
@node world_copyobj "AFC module: vectWorld / copyobj()"
NAME: copyobj(source_name, dest_name)
DESCRIPTION: copies the contents of source_name object to dest_name
object (except names).
INPUTS: name of two object_obj's.
RESULTS: FALSE if either of the objects has not been found.
SEE ALSO: @{" cloneobj() " LINK world_cloneobj}
@{" object_obj / copy() " LINK object_copy}
@endnode
*/
PROC copyobj(fname, dname) OF vectWorld
DEF o:PTR TO object_obj, d
IF (o:=self.posonobj(fname))=FALSE THEN RETURN FALSE
IF (d:=self.posonobj(dname))=FALSE THEN RETURN FALSE
ENDPROC o.copy(d)
->///
->/// PROC cloneobj(name, cname=NIL) OF vectWorld
/*
@node world_cloneobj "AFC module: vectWorld / cloneobj()"
NAME: cloneobj(name, new_name=NIL)
DESCRIPTION: creates a new object of name new_name (if supplied),
copies the contents of the object_obj 'name' in the newborn
object, and then links the latter to the vectWorld.
INPUTS: name of the object to be cloned,
new_name: name of the new object (if not supplied the
default is 'Copy_of_name').
RESULTS: FALSE if object 'name' not found.
SEE ALSO: @{" copyobj() " LINK world_copyobj}
@{" object_obj / clone() " LINK object_clone}
@endnode
*/
PROC cloneobj(name, cname=NIL) OF vectWorld
DEF o:PTR TO object_obj, c
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
c:=o.clone(cname)
self.obj.add(c)
ENDPROC TRUE
->///
->/// PROC applyobj(name) OF vectWorld
/*
@node world_applyobj "AFC module: vectWorld / applyobj()"
NAME: applyobj(name)
DESCRIPTION: same as @{"object_obj / apply()" LINK object_apply}.
INPUTS: name of the object to be modified.
RESULTS: FALSE if object not found.
SEE ALSO: @{" position() " LINK world_position}
@{" scale() " LINK world_scale}
@{" object_obj / apply() " LINK object_apply}
@endnode
*/
PROC applyobj(name) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.posonobj(name))=FALSE THEN RETURN FALSE
ENDPROC o.apply()
->///
->/// PROC projection() OF vectWorld
/*
@node world_projection "AFC module: vectWorld / projection()"
NAME: projection()
DESCRIPTION: transforms the 3D representation of the world in a 2D
representation, according with the chosen values of
rotantion angles (@{"setrot()" LINK world_setrot} method) and observer position
(@{"setobserver()" LINK world_setobserver} method).
You have to call this instruction before the drawing
routine, if you have performed some changes on the
vectWorld.
INPUTS: NONE
RESULTS: NONE
SEE ALSO: @{" object_obj / projection() " LINK object_projection}
@endnode
*/
PROC projection() OF vectWorld
DEF o:PTR TO object_obj
DEF s,c
DEF v:PTR TO vertex_obj, tv:PTR TO vertex_obj
DEF tvx,tvy,tvz
IF (o:=self.obj.first())<>FALSE
REPEAT
IF (v:=o.vertex.first())<>FALSE
-> copia vertici
tv:=o.tvert.first()
REPEAT
tv.x:=v.x
tv.y:=v.y
tv.z:=v.z
tv:=o.tvert.succ()
UNTIL (v:=o.vertex.succ())=FALSE
-> trasla locale
IF (o.pos_x<>0) OR (o.pos_y<>0) OR (o.pos_z<>0)
v:=o.tvert.first()
REPEAT
IF (o.pos_x<>0) THEN v.x:=v.x+o.pos_x
IF (o.pos_y<>0) THEN v.y:=v.y+o.pos_y
IF (o.pos_z<>0) THEN v.z:=v.z+o.pos_z
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> scala locale
IF (o.scale_x<>100) OR (o.scale_y<>100) OR (o.scale_z<>100)
v:=o.tvert.first()
REPEAT
IF (o.scale_x<>100) THEN v.x:=Div(Mul(v.x,o.scale_x),100)
IF (o.scale_y<>100) THEN v.y:=Div(Mul(v.y,o.scale_y),100)
IF (o.scale_z<>100) THEN v.z:=Div(Mul(v.z,o.scale_z),100)
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> scala globale
IF (self.scale_x<>100) OR (self.scale_y<>100) OR (self.scale_z<>100)
v:=o.tvert.first()
REPEAT
IF (self.scale_x<>100) THEN v.x:=Div(Mul(v.x,self.scale_x),100)
IF (self.scale_y<>100) THEN v.y:=Div(Mul(v.y,self.scale_y),100)
IF (self.scale_z<>100) THEN v.z:=Div(Mul(v.z,self.scale_z),100)
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> trasla globale
IF (self.trasl_x<>0) OR (self.trasl_y<>0) OR (self.trasl_z<>0)
v:=o.tvert.first()
REPEAT
IF (self.trasl_x<>0) THEN v.x:=v.x+self.trasl_x
IF (self.trasl_y<>0) THEN v.y:=v.y+self.trasl_y
IF (self.trasl_z<>0) THEN v.z:=v.z+self.trasl_z
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> rotazione x
IF self.rot_x<>0
s:=sin_table[self.rot_x]
c:=sin_table[limitangle(self.rot_x+90)]
v:=o.tvert.first()
REPEAT
tvx:=v.x
tvy:=Shr(Mul(c,v.y)+Mul(s,v.z),15)
tvz:=Shr(Mul(-s,v.y)+Mul(c,v.z),15)
v.x:=tvx ; v.y:=tvy ; v.z:=tvz
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> rotazione y
IF self.rot_y<>0
s:=sin_table[self.rot_y]
c:=sin_table[limitangle(self.rot_y+90)]
v:=o.tvert.first()
REPEAT
tvx:=Shr(Mul(c,v.x)+Mul(-s,v.z),15)
tvy:=v.y
tvz:=Shr(Mul(s,v.x)+Mul(c,v.z),15)
v.x:=tvx ; v.y:=tvy ; v.z:=tvz
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
-> rotazione z
IF self.rot_z<>0
s:=sin_table[self.rot_z]
c:=sin_table[limitangle(self.rot_z+90)]
v:=o.tvert.first()
REPEAT
tvx:=Shr(Mul(c,v.x)+Mul(s,v.y),15)
tvy:=Shr(Mul(-s,v.x)+Mul(c,v.y),15)
tvz:=v.z
v.x:=tvx ; v.y:=tvy ; v.z:=tvz
UNTIL (v:=o.tvert.succ())=FALSE
ENDIF
o.projection(self.observer_x,self.observer_y,self.observer_z)
ENDIF
UNTIL (o:=self.obj.succ())=FALSE
ENDIF
ENDPROC
->///
->/// PROC drawcode(rp,o:PTR TO object_obj) OF vectWorld
PROC drawcode(rp,o:PTR TO object_obj) OF vectWorld
DEF p1:PTR TO screen_pixel
DEF p2:PTR TO screen_pixel
DEF l:PTR TO line_obj
DEF dx1,dy1,dx2,dy2
IF (l:=o.line.first())<>FALSE -> ha almeno una linea?
REPEAT
IF (p1:=o.proj.item(l.startv))<>FALSE
IF (p2:=o.proj.item(l.endv))<>FALSE
dx1:=self.scrtrasl_x+Div(Mul(self.scrscale_x,p1.x),100)
dy1:=self.scrtrasl_y-Div(Mul(self.scrscale_y,p1.y),100)
dx2:=self.scrtrasl_x+Div(Mul(self.scrscale_x,p2.x),100)
dy2:=self.scrtrasl_y-Div(Mul(self.scrscale_y,p2.y),100)
SetAPen(rp, l.colour)
Move(rp, dx1, dy1)
Draw(rp, dx2, dy2)
ENDIF
ENDIF
UNTIL (l:=o.line.succ())=FALSE
ELSEIF (p1:=o.proj.first())<>FALSE -> altrimenti disegno solo pti
REPEAT
dx1:=self.scrtrasl_x+Div(Mul(self.scrscale_x,p1.x),100)
dy1:=self.scrtrasl_y-Div(Mul(self.scrscale_y,p1.y),100)
WritePixel(rp,dx1,dx2)
UNTIL (p1:=o.proj.succ())=FALSE
ENDIF
ENDPROC
->///
->/// PROC draw(rp) OF vectWorld
/*
@node world_draw "AFC module: vectWorld / draw()"
NAME: draw(rastport)
DESCRIPTION: draws the vectWorld in a wireframe fashion. If an object
has at least one line, then only its lines are drawn; if an
object has no lines, then its vertices are drawn. Rastport
is the address of a valid rastport in which to draw the
graphics.
The drawing is then traslated and scaled according to the
values entered with the @{"setaftertrasl()" LINK world_setaftertrasl} and
@{"setafterscale()" LINK world_setafterscale} methods.
Remember to @{"projection()" LINK world_projection} the vectWorld before drawing
it (you needn't do this if it's not the first time and
you've made no changes).
INPUTS: address of a rastport.
RESULTS: NONE
SEE ALSO: @{" drawfill() " LINK world_drawfill}
@{" projection() " LINK world_projection}
@endnode
*/
PROC draw(rp) OF vectWorld
DEF o:PTR TO object_obj
IF (o:=self.obj.first())<>FALSE
REPEAT
IF o.visible
self.drawcode(rp,o)
ENDIF
UNTIL (o:=self.obj.succ())=FALSE
ENDIF
ENDPROC
->///
->/// PROC drawfill(rp:PTR TO rastport, onlylines=FALSE) OF vectWorld
/*
@node world_drawfill "AFC module: vectWorld / drawfill()"
NAME: drawfill(rastport, onlylines=FALSE)
DESCRIPTION: draws the projected vectWorld with filled vectors.
The drawing is then traslated and scaled according to the
values entered with the @{"setaftertrasl()" LINK world_setaftertrasl} and
@{"setafterscale()" LINK world_setafterscale} methods.
Clipping is made according to the dimensions of the
screen area entered with the @{"setdisplay()" LINK world_setdisplay} method.
If the onlylines parameter is set to TRUE, then also
objects without surfaces are drawn.
Remember to @{"projection()" LINK world_projection} the vectWorld before drawing
it (you needn't do this if it's not the first time and
you've made no changes).
You must call the @{"init3D()" LINK world_init3d} routine at least one time
before drawing any filled graphics.
INPUTS: address of a rastport in which to draw the graphics.
RESULTS: NONE
SEE ALSO: Important: @{" init3D() " LINK world_init3d}
@{" projection() " LINK world_projection}
@endnode
*/
PROC drawfill(rp:PTR TO rastport, onlylines=FALSE) OF vectWorld
DEF o:PTR TO object_obj
DEF s:PTR TO surface_obj, flag=FALSE
DEF p0:PTR TO vertex_obj, p1:PTR TO vertex_obj, p2:PTR TO vertex_obj
DEF rx,ry,rz, q, pippo:PTR TO stuff, sum
DEF pix:PTR TO screen_pixel, dx,dy, el:PTR TO stuff
DEF sve:PTR TO surface_vertex, ind=0
DEF v:PTR TO vertex_obj, w:PTR TO vertex_obj, r:PTR TO vertex_obj
DEF look:PTR TO vertex_obj
NEW v ; NEW w ; NEW r ; NEW look
IF (pippo:=self.surflist.first())
REPEAT
END pippo
UNTIL (pippo:=self.surflist.succ())=FALSE
self.surflist.clear()
ENDIF
IF (o:=self.obj.first())<>FALSE
REPEAT
IF o.visible
IF (s:=o.surface.first())<>FALSE
REPEAT
IF s.vertex.numitems()>=3
sve:=s.vertex.first() -> vertice 0
p0:=o.tvert.item(sve.num)
sve:=s.vertex.succ() -> vertice 1
p1:=o.tvert.item(sve.num)
sve:=s.vertex.succ() -> vertice 2
p2:=o.tvert.item(sve.num)
v.x:=p1.x-p0.x
v.y:=p1.y-p0.y
v.z:=p1.z-p0.z
w.x:=p2.x-p0.x
w.y:=p2.y-p0.y
w.z:=p2.z-p0.z
rx, ry, rz:=crossprod(v,w)
r.x:=rx ; r.y:=ry ; r.z:=rz
look.x:=p0.x-self.observer_x
look.y:=p0.y-self.observer_y
look.z:=p0.z-self.observer_z
q:=dotprod(look,r)
IF q<0 -> dovrebbe essere q>0 ma la terna e' sisistrorsa
NEW pippo.stuff()
StrCopy(pippo.obj,o.name)
pippo.surf:=o.surface.numpos()
sum:=0
sve:=s.vertex.first()
REPEAT
p0:=o.tvert.item(sve.num)
sum:=sum+p0.z
UNTIL (sve:=s.vertex.succ())=FALSE
sum:=Div(sum,s.vertex.numitems())
pippo.avg:=Mul(-1,sum)
IF (el:=self.surflist.first())
flag:=FALSE
REPEAT
IF el.avg>pippo.avg
flag:=TRUE
IF self.surflist.numpos()>0
self.surflist.prev()
self.surflist.insert(pippo)
ELSE
self.surflist.add(pippo,NM_ADD_HEAD)
ENDIF
ELSE
el:=self.surflist.succ()
IF el=FALSE
flag:=TRUE
self.surflist.add(pippo)
ENDIF
ENDIF
UNTIL flag=TRUE
ELSE
self.surflist.add(pippo)
ENDIF
ENDIF
ENDIF
UNTIL (s:=o.surface.succ())=FALSE
ELSE -> no surfaces
IF onlylines THEN self.drawcode(rp,o)
ENDIF
ENDIF
UNTIL (o:=self.obj.succ())=FALSE
IF (pippo:=self.surflist.first())<>FALSE
rp.areainfo:=self.areai
rp.tmpras:=self.tras
REPEAT
ind:=0
o:=self.posonobj(pippo.obj)
s:=o.surface.item(pippo.surf)
IF (sve:=s.vertex.first())
REPEAT
pix:=o.proj.item(sve.num)
dx:=self.scrtrasl_x+Div(Mul(self.scrscale_x,pix.x),100)
dy:=self.scrtrasl_y-Div(Mul(self.scrscale_y,pix.y),100)
ind:=self.clippoint(rp,dx,dy,o,s,ind)
UNTIL (sve:=s.vertex.succ())=FALSE
SetAPen(rp,s.colour)
AreaEnd(rp)
ENDIF
UNTIL (pippo:=self.surflist.succ())=FALSE
ENDIF
ENDIF
END v ; END w ; END r ; END look
ENDPROC
->///
->/// PROC setobserver(ox,oy,oz) OF vectWorld
/*
@node world_setobserver "AFC module: vectWorld / setobserver()"
NAME: setobserver(x, y, z)
DESCRIPTION: sets the observer position.
INPUTS: coordinates of the observer.
RESULTS: NONE
SEE ALSO:
@endnode
*/
PROC setobserver(ox,oy,oz) OF vectWorld
self.observer_x:=ox
self.observer_y:=oy
self.observer_z:=oz
ENDPROC
->///
->/// PROC setscale(sx,sy,sz) OF vectWorld
/*
@node world_setscale "AFC module: vectWorld / setscale()"
NAME: setscale(x, y, z)
DESCRIPTION: the three scale factors will be applied to the whole
vectWorld before projecting it. They are entered as a
percentage: 100 means original dimensions, 50 means a
half, and so on...
This is a 3D operation: compare it with
@{"setafterscale()" LINK world_setafterscale}
INPUTS: scaling factors in the three directions.
RESULTS: NONE
SEE ALSO: @{" setafterscale() " LINK world_setafterscale}
@endnode
*/
PROC setscale(sx,sy,sz) OF vectWorld
IF sx<=0 THEN sx:=100
IF sy<=0 THEN sy:=100
IF sz<=0 THEN sz:=100
self.scale_x:=sx
self.scale_y:=sy
self.scale_z:=sz
ENDPROC
->///
->/// PROC settrasl(tx,ty,tz) OF vectWorld
/*
@node world_settrasl "AFC module: vectWorld / settrasl()"
NAME: settrasl(tx, ty, tz)
DESCRIPTION: traslates the whole vectWorld by the specified amounts
before projecting it.
This is a 3D operation: compare it with
@{"setaftertrasl()" LINK world_setaftertrasl}
The traslation is done before any rotation is performed.
INPUTS: traslation amounts in the three directions.
RESULTS: NONE
SEE ALSO: @{" setaftertrasl() " LINK world_setaftertrasl}
@endnode
*/
PROC settrasl(tx,ty,tz) OF vectWorld
self.trasl_x:=tx
self.trasl_y:=ty
self.trasl_z:=tz
ENDPROC
->///
->/// PROC setrot(rx,ry,rz) OF vectWorld
/*
@node world_setrot "AFC module: vectWorld / setrot()"
NAME: setrot(x, y, z)
DESCRIPTION: rotates the whole vectWorld around the three axes by the
specified amounts.
INPUTS: angles of rotation around the three axes (degrees).
RESULTS: NONE
SEE ALSO:
@endnode
*/
PROC setrot(rx,ry,rz) OF vectWorld
self.rot_x:=limitangle(rx)
self.rot_y:=limitangle(ry)
self.rot_z:=limitangle(rz)
ENDPROC
->///
->/// PROC setafterscale(sx,sy) OF vectWorld
/*
@node world_setafterscale "AFC module: vectWorld / setafterscale()"
NAME: setafterscale(x, y)
DESCRIPTION: scales the projected world while drawing it to adapt it to
the screen area. The scaling factors are entered as a
percentage: 100 means original dimensions, 50 means a
half, and so on...
This is a 2D operation: compare it with @{"setscale()" LINK world_setscale}
INPUTS: scaling factors in the two directions.
RESULTS: NONE
SEE ALSO: @{" setscale() " LINK world_setscale}
@endnode
*/
PROC setafterscale(sx,sy) OF vectWorld
IF sx<=0 THEN sx:=100
IF sy<=0 THEN sy:=100
self.scrscale_x:=sx
self.scrscale_y:=sy
ENDPROC
->///
->/// PROC setaftertrasl(tx,ty) OF vectWorld
/*
@node world_setaftertrasl "AFC module: vectWorld / setaftertrasl()"
NAME: setaftertrasl(x, y)
DESCRIPTION: translates the origin of the screen coordinate system
(default: top left-hand corner, as usual).
This is a 2D operation: compare it with @{"settrasl()" LINK world_settrasl}
INPUTS: traslation factors in the two directions.
RESULTS: NONE
SEE ALSO: @{" settrasl() " LINK world_settrasl}
@endnode
*/
PROC setaftertrasl(tx,ty) OF vectWorld
self.scrtrasl_x:=tx
self.scrtrasl_y:=ty
ENDPROC
->///
->/// PROC setdisplay(w,h) OF vectWorld
/*
@node world_setdisplay "AFC module: vectWorld / setdisplay()"
NAME: setdisplay(width, height)
DESCRIPTION: used to enter the screen area dimensions. These are used
in the allocation of the extra bitplane in the @{"init3D()" LINK world_init3d}
routine, and in the clipping of graphics in the
@{"drawfill()" LINK world_drawfill} method.
INPUTS: width and height of the drawing area (defaults are:
width=320, height=256).
RESULTS: NONE
SEE ALSO:
@endnode
*/
PROC setdisplay(w,h) OF vectWorld
IF w<=0 THEN w:=320
IF h<=0 THEN h:=256
self.d_width:=w
self.d_height:=h
ENDPROC
->///
->/// PROC init3D(bufon=TRUE,dispon=TRUE) OF vectWorld
/*
@node world_init3d "AFC module: vectWorld / init3D()"
NAME: init3D(bufon=TRUE, dispon=TRUE)
DESCRIPTION: allocates the resources needed by the @{"drawfill()" LINK world_drawfill} method
to draw filled vectors: you must call this routine before
any call to drawfill() is made.
It allocates a buffer needed by the operating system to
store the vectors before they are drawn, and an extra
bitplane to allow the drawing of filled areas. If, in a
second time, you change the dimensions of the screen area,
you have to recall this routine to update the dimensions of
the extra bitplane; in the same manner, if you add lots of
surfaces to your world, you have to call this routine to
adapt the buffer dimensions to the new situation (otherwise
you can get only partial rendering).
You needn't do both the operations every time you call
the init3D method, infact the two flags mean:
bufon =TRUE -> resize the buffer
dispon=TRUE -> resize the extra bitplane.
The dimensions of the screen area are entered with the
@{"setdisplay()" LINK world_setdisplay} method, and they are used also for graphic
clipping purposes.
INPUTS: flags described above.
RESULTS: raises some exceptions if memory allocation fails (see the
@{"Error Table" LINK Error_Table}).
SEE ALSO: @{" drawfill() " LINK world_drawfill}
@endnode
*/
PROC init3D(bufon=TRUE,dispon=TRUE) OF vectWorld
DEF o:PTR TO object_obj
-> DEF s:PTR TO surface_obj
DEF sum=0
IF (o:=self.obj.first())<>FALSE
REPEAT
/* IF (s:=o.surface.first())<>FALSE
REPEAT
sum:=sum+s.vertex.numitems()
UNTIL (s:=o.surface.succ())=FALSE
ENDIF
*/
sum:=sum+o.vertex.numitems()
UNTIL (o:=self.obj.succ())=FALSE
ENDIF
IF sum=0 THEN RETURN
IF self.surflist=NIL THEN NEW self.surflist.nodemaster()
IF self.areai=NIL
NEW self.areai
IF self.areai=NIL THEN Raise(WORLD_ERR_AREAINFO)
ENDIF
IF self.tras=NIL
NEW self.tras
IF self.tras=NIL THEN Raise(WORLD_ERR_TEMPRAS)
ENDIF
IF bufon=TRUE
IF self.buffer<>NIL
FreeVec(self.buffer)
self.buffer:=NIL
ENDIF
self.buffer:=AllocVec(5*(sum*2),MEMF_CLEAR)
IF self.buffer=NIL THEN Raise(WORLD_ERR_VECTBUFFER)
InitArea(self.areai,self.buffer,(sum*2))
ENDIF
IF dispon=TRUE
IF self.bplane<>NIL
FreeRaster(self.bplane,self.dw_old,self.dh_old)
self.bplane:=NIL
ENDIF
self.dw_old:=self.d_width
self.dh_old:=self.d_height
self.bplane:=AllocRaster(self.d_width,self.d_height)
IF self.bplane=NIL THEN Raise(WORLD_ERR_BITPLANE)
InitTmpRas(self.tras,self.bplane,RASSIZE(self.d_width,self.d_height))
ENDIF
ENDPROC
->///
->/// PROC version() OF vectWorld
/*
@node world_version "AFC module: vectWorld / version()"
NAME: version()
DESCRIPTION: returns version and revision of vectWorld module
INPUTS: NONE
RESULTS: version, revision
SEE ALSO:
@endnode
*/
PROC version() OF vectWorld IS WORLD_VERSION, WORLD_REVISION
-> ///
-> clipping
->/// PROC clipx(rp,dx,dy,x,y,rout,ind) OF vectWorld
PROC clipx(rp,dx,dy,x,y,rout,ind) OF vectWorld
DEF m, ndx,ndy
IF (x-dx)<>0
IF dx<0
m:=Mul((dy-y),dx)
ndy:=dy+Div(m,(x-dx))
IF (ndy>=0) AND (ndy<=(self.d_height-1))
IF (ndy>=Min(dy,y)) AND (ndy<=Max(dy,y))
rout(rp,0,ndy)
ind:=1
ENDIF
ENDIF
ELSE
ndx:=dx-(self.d_width-1)
m:=Mul((dy-y),ndx)
ndy:=dy+Div(m,(x-dx))
IF (ndy>=0) AND (ndy<=(self.d_height-1))
IF (ndy>=Min(dy,y)) AND (ndy<=Max(dy,y))
rout(rp,(self.d_width-1),ndy)
ind:=1
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC ind
->///
->/// PROC clipy(rp,dx,dy,x,y,rout,ind) OF vectWorld
PROC clipy(rp,dx,dy,x,y,rout,ind) OF vectWorld
DEF m,ndx,ndy
IF (dy-y)<>0
IF dy<0
m:=Mul((x-dx),dy)
ndx:=dx+Div(m,(dy-y))
IF (ndx>=0) AND (ndx<=(self.d_width-1))
IF (ndx>=Min(dx,x)) AND (ndx<=Max(dx,x))
rout(rp,ndx,0)
ind:=1
ENDIF
ELSE
IF (ndx<0) AND (Min(dx,x)<0) THEN (rout(rp,0,0) BUT ind:=1)
IF (ndx>(self.d_width-1)) AND (Max(dx,x)>(self.d_width-1))
rout(rp,(self.d_width-1),0)
ind:=1
ENDIF
ENDIF
ELSE
ndy:=dy-(self.d_height-1)
m:=Mul((x-dx),ndy)
ndx:=dx+Div(m,(dy-y))
IF (ndx>=0) AND (ndx<=(self.d_width-1))
IF (ndx>=Min(dx,x)) AND (ndx<=Max(dx,x))
rout(rp,ndx,(self.d_height-1))
ind:=1
ENDIF
ELSE
IF (ndx<0) AND (Min(dx,x)<0) THEN (rout(rp,0,(self.d_height-1)) BUT ind:=1)
IF (ndx>(self.d_width-1)) AND (Max(dx,x)>(self.d_width-1))
rout(rp,(self.d_width-1),(self.d_height-1))
ind:=1
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC ind
->///
->/// PROC firstdraw(rp,x,y)
PROC firstdraw(rp,x,y) IS AreaMove(rp,x,y)
->///
->/// PROC nextdraw(rp,x,y)
PROC nextdraw(rp,x,y) IS AreaDraw(rp,x,y)
->///
->/// PROC clippoint(rp,dx,dy,o:PTR TO object_obj,s:PTR TO surface_obj,pind) OF vectWorld
PROC clippoint(rp,dx,dy,o:PTR TO object_obj,s:PTR TO surface_obj,pind) OF vectWorld
DEF pdraw:PTR TO LONG, pixset=NIL
DEF px,py, pix:PTR TO screen_pixel, sve:PTR TO surface_vertex
pdraw:=[{firstdraw},{nextdraw}]
IF ((dx>=0) AND (dx<=(self.d_width-1))) AND ((dy>=0) AND (dy<=(self.d_height-1)))
pixset:=pdraw[pind] ; pind:=1
pixset(rp,dx,dy)
ELSE
IF ((dy<0) OR (dy>(self.d_height-1)))
-> collego con vertice precedente
s.vertex.push()
IF (sve:=s.vertex.prev())=FALSE
sve:=s.vertex.last()
ENDIF
s.vertex.pop()
pix:=o.proj.item(sve.num)
px:=self.scrtrasl_x+Div(Mul(self.scrscale_x,pix.x),100)
py:=self.scrtrasl_y-Div(Mul(self.scrscale_y,pix.y),100)
pind:=self.clipy(rp,dx,dy,px,py,pdraw[pind],pind)
-> collego con vertice successivo
s.vertex.push()
IF (sve:=s.vertex.succ())=FALSE
sve:=s.vertex.first()
ENDIF
s.vertex.pop()
pix:=o.proj.item(sve.num)
px:=self.scrtrasl_x+Div(Mul(self.scrscale_x,pix.x),100)
py:=self.scrtrasl_y-Div(Mul(self.scrscale_y,pix.y),100)
pind:=self.clipy(rp,dx,dy,px,py,pdraw[pind],pind)
ENDIF
IF (dx<0) OR (dx>(self.d_width-1))
-> collego con vertice precedente
s.vertex.push()
IF (sve:=s.vertex.prev())=FALSE
sve:=s.vertex.last()
ENDIF
s.vertex.pop()
pix:=o.proj.item(sve.num)
px:=self.scrtrasl_x+Div(Mul(self.scrscale_x,pix.x),100)
py:=self.scrtrasl_y-Div(Mul(self.scrscale_y,pix.y),100)
pind:=self.clipx(rp,dx,dy,px,py,pdraw[pind],pind)
-> collego con vertice successivo
s.vertex.push()
IF (sve:=s.vertex.succ())=FALSE
sve:=s.vertex.first()
ENDIF
s.vertex.pop()
pix:=o.proj.item(sve.num)
px:=self.scrtrasl_x+Div(Mul(self.scrscale_x,pix.x),100)
py:=self.scrtrasl_y-Div(Mul(self.scrscale_y,pix.y),100)
pind:=self.clipx(rp,dx,dy,px,py,pdraw[pind],pind)
ENDIF
ENDIF
ENDPROC pind
->///
-> General purpose routines
->/// PROC limitangle(a)
/*
@node world_limitangle "AFC module: procedure / limitangle()"
NAME: limitangle(angle)
DESCRIPTION: bounds the angle in range [0-359] degrees.
INPUTS: angle to be wrapped.
RESULTS: angle in the range [0-359] degrees
SEE ALSO:
@endnode
*/
PROC limitangle(a)
IF a<0
REPEAT
a:=a+360
UNTIL a>=0
ENDIF
IF a>359
REPEAT
a:=a-360
UNTIL a<359
ENDIF
ENDPROC a
->///
->/// PROC crossprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj)
/*
@node world_crossprod "AFC module: procedure / crossprod()"
NAME: crossprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj)
DESCRIPTION: this is the vector product between the two vectors 'a' and
'b'. The two arguments are defined as vertex_obj because
points in three-space and three-dimensional vectors share
the same structure (remember: points can be represented as
vectors from the origin).
The vectors have three fields: a.x, a.y and a.z; you
fill in these fields and call the routine: it returns the
three components of the resulting vector.
INPUTS: two (pointers to) vectors.
RESULTS: three return values, representing the three components of
the resulting vector, in the order: x, y, z.
SEE ALSO: @{" dotprod() " LINK world_dotprod}
@endnode
*/
PROC crossprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj)
DEF vx,vy,vz
vx:=Mul(a.y,b.z)-Mul(a.z,b.y)
vy:=Mul(a.z,b.x)-Mul(a.x,b.z)
vz:=Mul(a.x,b.y)-Mul(a.y,b.x)
ENDPROC vx, vy, vz
->///
->/// PROC dotprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj)
/*
@node world_dotprod "AFC module: procedure / dotprod()"
NAME: dotprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj)
DESCRIPTION: this is the scalar product between the two vectors 'a' and
'b'. See the observations about points and vectors in the
@{"crossprod()" LINK world_crossprod} procedure.
INPUTS: two (pointers to) vectors.
RESULTS: scalar product of the two vectors.
SEE ALSO: @{" crossprod() " LINK world_crossprod}
@endnode
*/
PROC dotprod(a:PTR TO vertex_obj, b:PTR TO vertex_obj) IS Mul(a.x,b.x)+Mul(a.y,b.y)+Mul(a.z,b.z)
-> ///
-> /// fillSinTable()
/*
@node world_fillsintable "AFC module: procedure / fillSinTable()"
NAME: fillSinTable()
DESCRIPTION: this is used to fill in a pointer to the table of sines:
of course, sines for rotations are not calculated realtime,
but peeked from this table. The table is automatically
filled when you create the first vectWorld object, so, in
general, you have not to do this task by hand. On the
other hand, if you don't fill the table before accessing it
you can crash your machine.
INPUTS: NONE
RESULTS: NONE
SEE ALSO:
@endnode
*/
PROC fillSinTable()
-> DEF x,s[15]:STRING
sin_table:=[0,572,1144,1715,
2286,2856,3425,3993,
4560,5126,5690,6252,
6813,7371,7927,8481,
9032,9580,10126,10668,
11207,11743,12275,12803,
13328,13848,14365,14876,
15384,15886,16384,16877,
17364,17847,18324,18795,
19261,19720,20174,20622,
21063,21498,21926,22348,
22763,23170,23571,23965,
24351,24730,25102,25466,
25822,26170,26510,26842,
27166,27482,27789,28088,
28378,28660,28932,29197,
29452,29698,29935,30163,
30382,30592,30792,30983,
31164,31336,31499,31651,
31795,31928,32052,32166,
32270,32365,32449,32524,
32588,32643,32688,32723,
32748,32763,32768,32763,
32748,32723,32688,32643,
32588,32524,32449,32365,
32270,32166,32052,31928,
31795,31651,31499,31336,
31164,30983,30792,30592,
30382,30163,29935,29698,
29452,29196,28932,28660,
28378,28088,27789,27482,
27166,26842,26510,26170,
25822,25466,25102,24730,
24351,23965,23571,23170,
22763,22348,21926,21498,
21063,20622,20174,19720,
19261,18795,18324,17847,
17364,16877,16384,15886,
15384,14876,14365,13848,
13328,12804,12275,11743,
11207,10668,10126,9581,
9032,8481,7927,7371,
6813,6253,5690,5126,
4561,3994,3425,2856,
2286,1715,1144,572,
0,-572,-1143,-1715,
-2286,-2856,-3425,-3993,
-4560,-5126,-5690,-6252,
-6813,-7371,-7927,-8481,
-9032,-9580,-10126,-10668,
-11207,-11743,-12275,-12803,
-13328,-13848,-14364,-14876,
-15383,-15886,-16384,-16877,
-17364,-17847,-18323,-18795,
-19260,-19720,-20174,-20621,
-21063,-21498,-21926,-22348,
-22762,-23170,-23571,-23965,
-24351,-24730,-25102,-25465,
-25821,-26169,-26510,-26842,
-27166,-27481,-27789,-28087,
-28378,-28659,-28932,-29196,
-29452,-29698,-29935,-30163,
-30382,-30591,-30792,-30983,
-31164,-31336,-31499,-31651,
-31795,-31928,-32052,-32166,
-32270,-32365,-32449,-32524,
-32588,-32643,-32688,-32723,
-32748,-32763,-32768,-32763,
-32748,-32723,-32688,-32643,
-32589,-32524,-32449,-32365,
-32270,-32166,-32052,-31928,
-31795,-31652,-31499,-31336,
-31164,-30983,-30792,-30592,
-30382,-30163,-29935,-29698,
-29452,-29197,-28933,-28660,
-28378,-28088,-27789,-27482,
-27166,-26842,-26510,-26170,
-25822,-25466,-25102,-24731,
-24352,-23965,-23572,-23171,
-22763,-22348,-21927,-21498,
-21063,-20622,-20174,-19721,
-19261,-18795,-18324,-17847,
-17365,-16877,-16385,-15887,
-15384,-14877,-14365,-13849,
-13329,-12804,-12276,-11744,
-11208,-10669,-10127,-9581,
-9033,-8482,-7928,-7372,
-6814,-6253,-5691,-5127,
-4561,-3994,-3426,-2857,
-2287,-1716,-1144,-573]
->x:=!(sin_table[90]!)/32768.0
->WriteF('sin90: \s\n',RealF(s,x,8))
ENDPROC
-> ///
/*
-> /// buildSinTable()
PROC buildSinTable()
DEF x,t,a,s[20]:STRING
DEF y,fh
IF (fh:=Open('ram:sin_table',MODE_NEWFILE))=NIL
WriteF('no file\n')
CleanUp(0)
ENDIF
a:=0.0
FOR t:=0 TO 359
x:=!Fsin(!a)
y:=!(!x)*32768.0! ;
StringF(s,'\d,',y)
Write(fh,s,StrLen(s))
IF Mod(t+1,4)=0 THEN Write(fh,'\n',1)
a:=!a+0.01745329
IF CtrlC()
Close(fh)
CleanUp(0)
ENDIF
ENDFOR
Close(fh)
ENDPROC
-> ///
*/
#ifdef WORLD_TEST
PROC main() HANDLE
DEF scene:PTR TO vectWorld
DEF scr=NIL:PTR TO screen, rp, vp:PTR TO viewport
DEF win=NIL:PTR TO window, port:PTR TO mp
DEF msg:PTR TO intuimessage, class, code
DEF oox,ooy,ooz, rrx,rry,rrz
DEF bm2:PTR TO bitmapper, rp2, bitmap2, ri:PTR TO rasinfo
DEF usebm=0, scrbm
-> fillSinTable() -> this IS done automatically by the following
NEW scene.vectWorld()
scene.addobj('cube')
scene.addobj('axis')
scene.addobj('pyramid')
scene.fastsetvert('cube',[-50,50,-50, 50,50,-50, 50,-50,-50, -50,-50,-50,
-50,50,50, 50,50,50, 50,-50,50, -50,-50,50]:vertex_obj)
scene.fastsetline('cube',[0,1,2, 1,2,2, 2,3,2, 3,0,2, 4,5,2, 5,6,2, 6,7,2, 7,4,2,
0,4,2, 1,5,2, 2,6,2, 3,7,2]:line_obj)
scene.fastsetvert('axis',[0,0,0, 100,0,0, 0,100,0, 0,0,100]:vertex_obj)
scene.fastsetline('axis',[0,1,3, 0,2,4, 0,3,5]:line_obj)
scene.fastsetvert('pyramid',[0,60,-50, 50,60,-50, 50,60,50, 0,60,50, 25,120,0]:vertex_obj)
scene.fastsetline('pyramid',[0,1,6, 1,2,6, 2,3,6, 3,0,6,
0,4,6, 1,4,6, 2,4,6, 3,4,6]:line_obj)
scene.setsurface('cube',0,[0,1,2,3],2)
scene.setsurface('cube',1,[0,4,5,1],3)
scene.setsurface('cube',2,[7,6,5,4],4)
scene.setsurface('cube',3,[3,2,6,7],5)
scene.setsurface('cube',4,[0,3,7,4],6)
scene.setsurface('cube',5,[1,5,6,2],7)
scene.setsurface('pyramid',0,[0,1,2,3],3)
scene.setsurface('pyramid',1,[0,4,1],2)
scene.setsurface('pyramid',2,[3,4,0],4)
scene.setsurface('pyramid',3,[2,4,3],5)
scene.setsurface('pyramid',4,[1,4,2],6)
-> scene.visible('pyramid',FALSE)
-> scene.cloneobj('cube', 'cube2')
-> scene.position('cube2',-50,-50,-50)
/* objectList(scene)
WriteF('\n')
dumpObject(scene.getobj('cube'))
WriteF('\n')
dumpObject(scene.getobj('cube2'))
*/
scene.setdisplay(320,256)
scene.init3D()
scene.setaftertrasl(160,128)
scene.setobserver(0,0,-200)
scene.setafterscale(200,200)
scr:=OpenScreenTagList(NIL,[SA_TOP,0,
SA_LEFT,0,
SA_WIDTH,320,
SA_HEIGHT,256,
SA_DEPTH,3,
SA_TITLE,'Routines3D',
SA_SHOWTITLE,FALSE,
0,0])
IF scr=NIL THEN Raise("SCR")
vp:=scr.viewport
ri:=vp.rasinfo
scrbm:=ri.bitmap
SetRGB4(vp,3,15,0,0)
SetRGB4(vp,4,0,15,0)
SetRGB4(vp,5,0,0,15)
SetRGB4(vp,7,12,12,0)
NEW bm2.bitmapper()
bm2.allocbitmap(320,256,3,TRUE)
rp2:=bm2.rastport()
bitmap2:=bm2.bitmap()
win:=OpenWindowTagList(NIL,[WA_TOP,0,
WA_LEFT,0,
WA_WIDTH,320,
WA_HEIGHT,256,
WA_TITLE,'Routines3D',
WA_FLAGS,WFLG_ACTIVATE OR WFLG_SMART_REFRESH OR WFLG_BACKDROP OR WFLG_BORDERLESS,
WA_IDCMP,IDCMP_RAWKEY,
WA_CUSTOMSCREEN,scr,
0,0])
IF win=NIL THEN Raise("WIN")
rp:=win.rport
port:=win.userport
oox:=0 ; ooy:=0 ; ooz:=-200
rrx:=0 ; rry:=0 ; rrz:=0
scene.projection()
scene.drawfill(rp)
usebm:=1-usebm
LOOP
Wait(Shl(1,port.sigbit))
REPEAT
IF (msg:=GetMsg(port))<>NIL
class:=msg.class
code:=msg.code
ReplyMsg(msg)
SELECT class
CASE IDCMP_RAWKEY
SELECT code
CASE $4C -> up arrow
ooy:=ooy+1
scene.setobserver(oox,ooy,ooz)
CASE $4D -> down arrow
ooy:=ooy-1
scene.setobserver(oox,ooy,ooz)
CASE $4E -> right arrow
oox:=oox+1
scene.setobserver(oox,ooy,ooz)
CASE $4F -> left arrow
oox:=oox-1
scene.setobserver(oox,ooy,ooz)
CASE $46 -> del
ooz:=ooz-1
scene.setobserver(oox,ooy,ooz)
CASE $5F -> help
ooz:=ooz+1
scene.setobserver(oox,ooy,ooz)
CASE $10 -> q
rrx:=rrx-1
scene.setrot(rrx,rry,rrz)
CASE $11 -> w
rrx:=rrx+1
scene.setrot(rrx,rry,rrz)
CASE $20 -> a
rry:=rry-1
scene.setrot(rrx,rry,rrz)
CASE $21 -> s
rry:=rry+1
scene.setrot(rrx,rry,rrz)
CASE $31 -> z
rrz:=rrz-1
scene.setrot(rrx,rry,rrz)
CASE $32 -> x
rrz:=rrz+1
scene.setrot(rrx,rry,rrz)
CASE $40 -> space
oox:=0 ; ooy:=0 ; ooz:=-200
rrx:=0 ; rry:=0 ; rrz:=0
scene.setobserver(oox,ooy,ooz)
scene.setrot(rrx,rry,rrz)
CASE $45 -> esc
REPEAT
IF (msg:=GetMsg(port))<>NIL THEN ReplyMsg(msg)
UNTIL msg=NIL
Raise("end")
CASE $22 -> d
->scene.delsurface('cube',4)
->scene.setsurface('cube',3,[3,2,6],5)
->scene.setscale(100,50,100)
->scene.settrasl(100,0,0)
ENDSELECT
ENDSELECT
ENDIF
UNTIL msg=NIL
scene.projection()
SetAPen(IF usebm=0 THEN rp ELSE rp2, 0)
RectFill(IF usebm=0 THEN rp ELSE rp2, 0,0,320,256)
scene.drawfill(IF usebm=0 THEN rp ELSE rp2)
IF usebm=0 -> double buffering a mano (in uno schermo)
ri.bitmap:=scrbm
ELSE
ri.bitmap:=bitmap2
ENDIF
WaitTOF()
ScrollVPort(vp)
usebm:=1-usebm
ENDLOOP
EXCEPT DO
IF win THEN CloseWindow(win)
IF scr
ri.bitmap:=scrbm
CloseScreen(scr)
ENDIF
IF scene THEN END scene
IF bm2 THEN END bm2
describe3DException()
CleanUp(0)
ENDPROC
#endif