polygon winding with DrawPoly

BlitzMax Forums/BlitzMax Programming/polygon winding with DrawPoly

Are there any known issues with the winding of the vertexes when using DrawPoly? I've got a wierd situation where it looks like I can see through polygons that are drawn over other polygons. You kind of have to see it in action but here are some pictures.

should look like this


does look like this


Wouldn't you need some sort of Z sort to draw the polygons in the correct order?

Yeah I have one, I'm drawing them back to front. I can't figure this out. in the above picture the strip in the middle shouldn't be visible. It behaves like it blends the front and back polygons together on screen but I'm using SOLIDBLEND for the mode.

' this code adapted from one of ETROMIC's (Olof Hånell) effects
Strict

Framework BRL.GLMax2D

Import BRL.System
Import BRL.Basic
Import BRL.pngloader
Import BRL.Retro 

?Win32
	SetGraphicsDriver(GLMax2DDriver())
?
Graphics 640,480,0'32,60

Const NUM_DEGREES:Int = 20
Const NUM_SECTIONS:Int = 45
Const NUM_POINTS:Int = 5
Const ROTATION_SCALE:Int = 2
'Global baseColor:Int = 2895943
Global baseColor:Int = 13412915
Const bgColor:Int = 2895943
Global cylinderWidth:Int = 150
Global XZ_SCALE:Int = cylinderWidth Shr 1
Global circle_y_step:Int = GraphicsHeight()/NUM_SECTIONS
Global variation_speed:Float = 0.00021
Global cycledifference:Float = 0.022
Global fm:Float = 0.0
Global CP:CirclePlane[] = New CirclePlane[NUM_SECTIONS]
Global polys:Polygon[] = New Polygon[(NUM_SECTIONS-1) * (NUM_POINTS)]
For Local ip:Int = 0 Until polys.length
	polys[ip] = Polygon.Create()
Next
Global ptsZ:Int[] = New Int[polys.length]
Global colors:Color[] = New Color[polys.length]
For Local ic:Int = 0 Until polys.length
	colors[ic] = New Color
Next
Global order:Int[] = New Int[polys.length]


setupSections()

Global frames:Long = 0
Global fps:Long = 0
Global lastTime:Long = MilliSecs()

SetClsColor(44,48,71)

While Not KeyHit(KEY_ESCAPE)
	Cls ' clear the screen
	SetBlend(SOLIDBLEND)
	SetColor(255,255,255)
	SetAlpha(1)
	update()
	DoFPS()	
	Flip() ' flip the buffers
	FlushMem() ' garbage collection
Wend

Type Point
	Field x:Float
	Field y:Float
	'Field z:Float
	
	Method Set(x1:Float,y1:Float)',z1:Float)
		x=x1
		y=y1
		'z=z1
	End Method
End Type

Type Polygon
	Field points:Point[] = New Point[4]
	Field c:Color = New Color
	Field array:Float[] = New Float[6]
	
	Function Create:Polygon()
		Local p:Polygon= New Polygon
		For Local c:Int = 0 To 3
			p.points[c] = New Point
		Next
		Return p
	End Function
	
	Method firstPoints()
		'array[0] = points[0].x
		'array[1] = points[0].y
		'array[2] = points[1].x
		'array[3] = points[1].y
		'array[4] = points[2].x
		'array[5] = points[2].y
		array[0] = points[0].x
		array[1] = points[0].y
		array[2] = points[2].x
		array[3] = points[2].y
		array[4] = points[1].x
		array[5] = points[1].y
	End Method
	
	Method secondPoints()
		'array[0] = points[2].x
		'array[1] = points[2].y
		'array[2] = points[3].x
		'array[3] = points[3].y
		'array[4] = points[0].x
		'array[5] = points[0].y
		array[0] = points[2].x
		array[1] = points[2].y
		array[2] = points[0].x
		array[3] = points[0].y
		array[4] = points[3].x
		array[5] = points[3].y
	End Method
	
End Type

Type Color
	Field r:Int=255
	Field g:Int=255
	Field b:Int=255
	
	Method Set(r1:Float,g1:Float,b1:Float)
		r=r1
		g=g1
		b=b1
	End Method
End Type

Function rotPoints()
    Local diff:Float = 0
    For Local i:Int=0 Until NUM_SECTIONS
      'CP[i].rotateBy(Float(Float(ROTATION_SCALE)*Sin((fm+diff)*0.0174532925)))
      CP[i].rotateBy(Float(Float(ROTATION_SCALE)*Sin(fm+diff)))
      'CP[i].rotateBy(.5)
      diff:+cycledifference
      fm:+variation_speed
    Next
End Function

Function update()
	rotPoints()
	
    Local yStep:Float = Float(GraphicsHeight()) / Float(NUM_SECTIONS-1)
    Local yp:Float = 0
    Local xPush:Int = (GraphicsWidth() Shr 1) - (XZ_SCALE Shr 1)

    'Local pts:Polygon[] = New Polygon[(NUM_SECTIONS-1) * (NUM_POINTS)]
    'Local ptsZ:Int[] = New Int[polys.length]
    'Local colors:Color[] = New Color[polys.length]
    'Local order:Int[] = New Int[polys.length]

    Local n:Int = 0;
    Local p:Polygon;
    For Local i:Int=0 Until NUM_SECTIONS-1
      For Local j:Int=0 Until NUM_POINTS
        p = polys[n]'Polygon.Create();
		Local p0:Float[] = CP[i].GetPoint(j)
		Local p1:Float[] = CP[i].GetPoint(j+1)
		Local p2:Float[] = CP[i+1].GetPoint(j+1)
		Local p3:Float[] = CP[i+1].GetPoint(j)
        p.points[0].Set(Int(p0[0] + xPush +.5), Int(yp+.5))
        p.points[1].Set(Int(p1[0] + xPush +.5), Int(yp+.5))
        p.points[2].Set(Int(p2[0] + xPush +.5), Int(yp+yStep+.5))
        p.points[3].Set(Int(p3[0] + xPush +.5), Int(yp+yStep+.5))

        polys[n] = p;
        ptsZ[n] = Int(p0[1] + p1[1] + p2[1] + p3[1]) Shr 2

        Local c:Int = Int( ptsZ[n] - XZ_SCALE )
        Local base_r:Int = ((baseColor Shr 16) & 255) + c
        Local base_g:Int = ((baseColor Shr  8) & 255) + c
        Local base_b:Int = ((baseColor      ) & 255) + c

		'If j =2 Then
        '	base_r = ((bgColor Shr 16) & 255) + c
    	'   base_g = ((bgColor Shr  8) & 255) + c
	    '    base_b = ((bgColor      ) & 255) + c
		'EndIf

        If base_r>255 Then base_r = 255
        If base_g>255 Then base_g = 255
        If base_b>255 Then base_b = 255

        'colors[n] = New Color
		colors[n].Set(base_r,base_g,base_b)
		n:+1
      Next
      yp:+yStep
    Next
    order = zSort(ptsZ)

	SetBlend(SOLIDBLEND)
	SetColor(255,255,255)
	SetAlpha(1)
	
    Local nu:Int = order.length
    For Local i:Int=0 Until nu
		
		SetColor(colors[order[i]].r,colors[order[i]].g,colors[order[i]].b);
		
		polys[order[i]].firstPoints()
		DrawPoly(polys[order[i]].array);
		
		polys[order[i]].secondPoints()
		DrawPoly(polys[order[i]].array);
    Next
End Function  

Function zSort:Int[](ptsZs:Int[])
    Local sorted:Byte = False
    Local num:Int = ptsZs.length - 1
    Local back:Int[] = New Int[ptsZ.length]
    For Local i:Int=0 Until back.length
		back[i] = i
	Next
'	Rem
    While sorted=False
      sorted = True
      For Local i:Int=0 Until num
        If ptsZs[i] > ptsZs[i+1] Then
          Local backTemp:Int = back[i]
          Local tmp:Int = ptsZs[i]
          back[i] = back[i+1]
          ptsZs[i] = ptsZs[i+1]
          back[i+1] = backTemp
          ptsZs[i+1] = tmp
          sorted = False
        EndIf
      Next
    Wend
'EndRem
    Return back
End Function

Function DoFPS()
	SetBlend(SOLIDBLEND)
	SetColor(255,255,255)
	SetAlpha(1)
	DrawText "FPS: "+fps,0,0
	frames:+1
	If MilliSecs()-lastTime>=1000 Then 
		fps=frames
		frames=0
		lastTime=MilliSecs()
	EndIf
End Function

Function setupSections()
    Local sAngle:Float = 0
    Local aStep:Float = Float(NUM_DEGREES) / Float(NUM_SECTIONS)
    For Local i:Int=0 Until NUM_SECTIONS
      CP[i] = CirclePlane.Create(NUM_POINTS, XZ_SCALE, sAngle)
      sAngle:+aStep
    Next
End Function

Type CirclePlane
    Field numPoints:Int = 0
    Field rotation:Float = 0
    Field degreeStep:Double = 0
    Field ps:Float[,]
    Field psb:Float[,]
    Field scale:Int = 0
    Const X:Int = 0
    Const Z:Int = 1

    Function Create:CirclePlane(pointCount:Int, scale:Int, sRotation:Float)
		Local cp:CirclePlane = New CirclePlane
		cp.numPoints = pointCount
		cp.rotation = Float(sRotation)
		cp.scale = scale
		cp.degreeStep = Double(360) / Double(pointCount)
		cp.ps = New Float[pointCount,2]
		cp.rot()
		Return cp
    End Function

    Method rotateBy(deg:Float)
      rotation :+ deg
      rot()
    End Method

	Method GetPoint:Float[](which:Int)
		Local back:Float[] = New Float[2]
		back[0] = ps[which Mod numPoints,0]
		back[1] = ps[which Mod numPoints,1]
		Return back
	End Method
	
    Method rot()
      Local ang:Double = 0
      For Local i:Int=0 Until numPoints
        ps[i,X] = Int(Float(scale) * Cos(rotation + ang) + .5)
        ps[i,Z] = Int(Float(scale) * Cos(rotation + ang - (3.1416/2.0)) + Float(scale)+.5)
        ang:+degreeStep
      Next
    End Method
End Type


It looks like you still have some radians based maths in there, the 3.1416 at the bottom and things like cycledifference look a bit odd also...

If the original code is in radians I would recomend sticking with that and add your own RADSIN() and RADCOS() functions.

Hmm, here is the original Java code. it appears to be working with degrees everywhere except when it does the sin and cos calls because java expects radians.

package com.sas.specialfx.effects;
import com.sas.specialfx.Main;
import com.sas.specialfx.MouseController;
import com.sas.specialfx.DisplayObject;
import java.awt.*;
import java.awt.image.*;

public class EtromicEffect02 extends DisplayObject{
  private VolatileImage img;
  private int W, H;

  public EtromicEffect02(String propName){
    super();
    W = Main.getInstance().displayWidth;
    H = Main.getInstance().displayHeight;

    // turn off the cursor the framework handle turning it back on for the next effect
    MouseController.setMousePointer(Main.BLANK_CURSOR_NAME, Main.getInstance());

    init();
    setUpdateInterval(0);
  }

    public void cleanup() {
        img.flush();
    }

  public void display(Graphics g){
    g.setColor(Color.black);
    g.fillRect(0,0,W,H);
    blt(g);
  }
  public void update(long currentTime){
    updateImage();
    rotPoints();
  }

  private void init(){
    initVolatileImage();
    CP = new CirclePlane[NUM_SECTIONS];
    circle_y_step = H / NUM_SECTIONS;
    setupSections();
  }

  private void initVolatileImage(){
    if(img==null){
      img = Main.getInstance().getGraphicsConfiguration().createCompatibleVolatileImage(W, H);
    }
  }
//---------------------------------------------------------------------------------------------------------------------------------

  private void blt(Graphics g){
    if(img.contentsLost()) initVolatileImage();
    g.drawImage(img,0,0,null);
  }

/*
****************************************************************
****************************************************************
****************************************************************
****************************************************************
*/


  private final int NUM_DEGREES = 20;
  private final int NUM_SECTIONS = 45;
  private final int NUM_POINTS = 5;
  private final int ROTATION_SCALE = 2;
  private int baseColor = 0x2C3047;
  private final Color bgColor = new Color(0x2C3047);
  private int cylinderWidth = 150;
  private int XZ_SCALE = cylinderWidth >> 1;
  private int circle_y_step;
  private float variation_speed = 0.00021f;//0.00015f;
  private float cycledifference = 0.022f;
  private float fm = 0.0f;
  private CirclePlane CP[];

  private void setupSections(){
    int sAngle = 0;
    int aStep = NUM_DEGREES / NUM_SECTIONS;
    for(int i=0; i<NUM_SECTIONS; i++){
      CP[i] = new CirclePlane(NUM_POINTS, XZ_SCALE, sAngle);
      sAngle += aStep;
    }
  }

  private void updateImage(){
    Graphics img_g = img.getGraphics();
    float yStep = (float)H / (float)(NUM_SECTIONS-1);
    img_g.setColor(bgColor);
    img_g.fillRect(0,0,W,H);
    float yp = 0;
    int xPush = (W >> 1) - (XZ_SCALE >> 1);

    Polygon pts[] = new Polygon[(NUM_SECTIONS-1) * (NUM_POINTS)];
    int ptsZ[] = new int[pts.length];
    Color colors[] = new Color[pts.length];
    int order[] = new int[pts.length];

    int n = 0;
    Polygon p;
    for(int i=0; i<NUM_SECTIONS-1; i++){
      for(int j=0; j<NUM_POINTS; j++){
        p = new Polygon();
        float p0[] = CP[i].getPoint(j); //top left
        float p1[] = CP[i].getPoint(j+1); //top right
        float p2[] = CP[i+1].getPoint(j+1); //down right
        float p3[] = CP[i+1].getPoint(j); //down left

        p.addPoint(Math.round(p0[0] + xPush),Math.round(yp));
        p.addPoint(Math.round(p1[0] + xPush),Math.round(yp));
        p.addPoint(Math.round(p2[0] + xPush),Math.round(yp+yStep));
        p.addPoint(Math.round(p3[0] + xPush),Math.round(yp+yStep));

        pts[n] = p;
        ptsZ[n] = (int)(p0[1] + p1[1] + p2[1] + p3[1]) >> 2;

        int c = (int)( ptsZ[n] - XZ_SCALE );
        int base_r = ((baseColor >> 16) & 0xFF) + c;
        int base_g = ((baseColor >>  8) & 0xFF) + c;
        int base_b = ((baseColor      ) & 0xFF) + c;

        if(base_r>0xFF){ base_r = 0xFF;}
        if(base_g>0xFF){ base_g = 0xFF;}
        if(base_b>0xFF){ base_b = 0xFF;}

        int co_value = (base_r << 16) + (base_g<<8) + base_b;
        Color co = new Color(co_value);
        colors[n++] = co;
      }
      yp += yStep;
    }
    order = zSort(ptsZ);
    int nu = order.length;
    for(int i=0; i<nu; i++){
      img_g.setColor(colors[order[i]]);
      img_g.fillPolygon(pts[order[i]]);
    }
    img_g.dispose();
  }

  private int[] zSort(int ptsZ[]){
    boolean sorted = false;
    int num = ptsZ.length - 1;
    int back[] = new int[ptsZ.length];
    for(int i=0; i<back.length; i++){back[i] = i;}
    while(!sorted){
      sorted = true;
      for(int i=0; i<num; i++){
        if(ptsZ[i] > ptsZ[i+1]){
          int backTemp = back[i];
          int tmp = ptsZ[i];
          back[i] = back[i+1];
          ptsZ[i] = ptsZ[i+1];
          back[i+1] = backTemp;
          ptsZ[i+1] = tmp;
          sorted = false;
        }
      }
    }
    return back;
  }

  private void rotPoints(){
    float diff = 0f;
    for(int i=0; i<NUM_SECTIONS; i++){
      CP[i].rotateBy((float)(ROTATION_SCALE*Math.sin(fm+diff)));
      diff += cycledifference;
      fm += variation_speed;
    }
  }


/*
****************************************************************
****************************************************************
****************************************************************
****************************************************************
*/


//-------------- CirclePlane class
  private class CirclePlane{
    private int numPoints = 0;
    private float rotation = 0;
    private double degreeStep;
    private float ps[][];
    private float psb[][];
    private int scale = 0;
    private final int X = 0;
    private final int Z = 1;
    CirclePlane(int numPoints, int scale, int sRotation){
      this.numPoints = numPoints;
      this.rotation = (float)sRotation;
      this.scale = scale;
      degreeStep = 360d / (double)numPoints;
      ps = new float[numPoints][2];
      rot();
    }
    public void rotateBy(float deg){
      rotation += deg;
      rot();
    }
    private void rot(){
      double ang = 0;
      for(int i=0; i<numPoints; i++){
        ps[i][X] = Math.round(scale * Math.cos(Math.toRadians(rotation + ang)));
        ps[i][Z] = Math.round(scale * Math.cos(Math.toRadians(rotation + ang) - (Math.PI/2))) + scale;
        ang += degreeStep;
      }
    }
    public float[] getPoint(int which){
      return ps[which % (numPoints)];
    }
  }
//----------------------


}


so double check your radians to degrees stuff:
CP[i].rotateBy(Float(Float(ROTATION_SCALE)*Sin(180*(fm+diff)/Pi)))

ps[i,Z] = Int(Float(scale) * Cos(rotation + ang - 180) + Float(scale)+.5)

The only obvious problem is 3.1416/2.0, which is clearly Pi/2 i.e. radians.
Replace it with 90, the equivalent in degrees.

This gives Cos(rotation + ang - 90).

In fact, Cos(x - 90) and Sin(x) are the same. You may as well use Sin(rotation + ang).

Thanks guys that fixed it. :)