Seite 2 von 5

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 14:33
von Zudomon
Da hab ich doch etwas viele "end;" am Ende :D

Code: Alles auswählen

procedure UpdateRegister;
var
  i: Integer;
begin
  if state_Pass<0 then showmsg('Kein Pass aktiviert!');

  with D3DDevice do begin
    with Pass[state_Pass] do begin
      for i := 0 to high(PassSlot) do with PassSlot[i] do begin
        with ShaderConstant[Constant] do begin
          case ShaderType of
            st_VertexShader: begin
              case TypeOf of
                sct_Matrix4: SetVertexShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
            st_PixelShader: begin
              case TypeOf of
                sct_Matrix4: SetPixelShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 15:34
von Chromanoid
wie sind da die regeln für groß- und kleinschreibung? Also delphi ist das ja egal, aber dem leser nicht...

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 16:21
von Zudomon
Chromanoid hat geschrieben:wie sind da die regeln für groß- und kleinschreibung? Also delphi ist das ja egal, aber dem leser nicht...
Wie du schon sagt, Delphi ist das egal... und ich habe mir da halt meinen Stil angewöhnt...

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 20:07
von CodingCat
Wie zu allen Codebeispielen fällt mir auch zu diesem nur wieder ein: Delphi ist ganz offensichtlich die grässlichste Sprache der Welt. :P

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 20:13
von FlashbackOwl
Nee, Factor ist offensichtlich die grässlichste Sprache der Welt !
Beispiel vom HelloWorld- Programm(Hoffe das stimmt so :/ )

Code: Alles auswählen

USE: io
IN: hello-world

: hello ( -- ) "Hello, World!" print ;

MAIN: hello

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 22:49
von hagbard
Zudomon hat geschrieben:Da hab ich doch etwas viele "end;" am Ende :D

Code: Alles auswählen

procedure UpdateRegister;
var
  i: Integer;
begin
  if state_Pass<0 then showmsg('Kein Pass aktiviert!');

  with D3DDevice do begin
    with Pass[state_Pass] do begin
      for i := 0 to high(PassSlot) do with PassSlot[i] do begin
        with ShaderConstant[Constant] do begin
          case ShaderType of
            st_VertexShader: begin
              case TypeOf of
                sct_Matrix4: SetVertexShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
            st_PixelShader: begin
              case TypeOf of
                sct_Matrix4: SetPixelShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;
Wenn jemand dir dochmal einen Rat geben kann: Lass die Finger von 'With', dass ist ein Designfehler der Sprache und führt meisten zu unleserlichen Code auch wenn du weniger tippen musst. *duck*

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 23:07
von Zudomon
hagbard hat geschrieben:
Zudomon hat geschrieben:Da hab ich doch etwas viele "end;" am Ende :D

Code: Alles auswählen

procedure UpdateRegister;
var
  i: Integer;
begin
  if state_Pass<0 then showmsg('Kein Pass aktiviert!');

  with D3DDevice do begin
    with Pass[state_Pass] do begin
      for i := 0 to high(PassSlot) do with PassSlot[i] do begin
        with ShaderConstant[Constant] do begin
          case ShaderType of
            st_VertexShader: begin
              case TypeOf of
                sct_Matrix4: SetVertexShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
            st_PixelShader: begin
              case TypeOf of
                sct_Matrix4: SetPixelShaderConstantF(RegSlot, @Data[0], 4);
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;
Wenn jemand dir dochmal einen Rat geben kann: Lass die Finger von 'With', dass ist ein Designfehler der Sprache und führt meisten zu unleserlichen Code auch wenn du weniger tippen musst. *duck*
Das schlimme am "with" ist, dass es Fehler produzieren kann, wenn nämlich sich das with z.B. auf ein Element aus einem dynamischen Array bezieht, welches dann intern vergrößert wird... ich meine, damit kommt der nicht klar...
Naja, aber ich bin dankbar für das with, ansonsten gibt es ewig lange Konstrukte und meine Zeilen würden nicht mehr vollständig auf den Bildschirm passen... und dann verliere ich wirklich die Übersicht.

Es ist schade, dass es keine Defines gibt, sonst könnte man da nämlich auch damit abkürzen... in C++ hab ich damit richtig dreckig programmiert...

Erstmal schöne 1D-, 2D- und 3D-Schleifen

Code: Alles auswählen

#define forExt(i, t)              for(int (i)=0; (i)<int(t); (i)++)
#define forExt2D(i,j,t1,t2)       forExt(i, t1) forExt(j, t2)
#define forExt3D(i,j,k,t1,t2,t3)  forExt2D(i,j,t1,t2) forExt(k, t3)
Und dann daraus Vektor und Matrix Klassen bauen:

Code: Alles auswählen

#define VEC1(exp)  TVec3 r; forExt(i, 3) r.v[i]=exp; return r;
#define VEC2(exp)  forExt(i, 3) v[i]exp; return *this;

class TVec3{
  public:
    float v[3];
    TVec3&operator = (float s)   { forExt(i, 3) v[i]=s; return *this; };
    TVec3 operator - ()          { VEC1( -v[i]         ) };
    TVec3 operator - (TVec3 opp) { VEC1( v[i]-opp.v[i] ) };
    TVec3 operator - (float s)   { VEC1( v[i]-s        ) };
    TVec3 operator + (TVec3 opp) { VEC1( v[i]+opp.v[i] ) };
    TVec3 operator + (float s)   { VEC1( v[i]+s        ) };
    TVec3 operator * (float s)   { VEC1( v[i]*s        ) };
    TVec3 operator / (float s)   { DIV0( s, return operator=(0); , return operator*(1.0/s); ) };
    TVec3&operator -=(TVec3 opp) { VEC2( -=opp.v[i]    ) };
    TVec3&operator -=(float s)   { VEC2( -=s           ) };
    TVec3&operator +=(TVec3 opp) { VEC2( +=opp.v[i]    ) };
    TVec3&operator +=(float s)   { VEC2( +=s           ) };
    TVec3&operator *=(float s)   { VEC2( *=s           ) };
    TVec3&operator /=(float s)   { DIV0( s, return *this; , VEC2( /=s; ) ) };
    float&operator [](int index) { return v[index]; };
    float lngSQ()                { return sqr(v[0])+sqr(v[1])+sqr(v[2]); };
    float lng()                  { return sqrt(lngSQ()); };
    void writeTo( char *p )      { *(p++)=_Byte(v[0]); *(p++)=_Byte(v[1]); *p=_Byte(v[2]); } ;
};

TVec3 crt(float a,  float b,  float c)      { TVec3 r={a,b,c}; return r; };
float dot(TVec3 v1, TVec3 v2)               { float r=0; forExt(i,3) r+=v1[i]*v2[i]; return r; };
TVec3 crs(TVec3 v1, TVec3 v2)               { TVec3 r; forExt(i,3) r.v[i]=v1[(i+1)%3]*v2[(i+2)%3]-v1[(i+2)%3]*v2[(i+1)%3]; return r; };
TVec3 nrm(TVec3 v)                          { return v / v.lng(); }
TVec3 lrp(TVec3 v1, TVec3 v2, float s)      { TVec3 r; forExt(i,3)r.v[i]=v1[i]+s*(v2[i]-v1[i]); return r; };
TVec3 normal(TVec3 v1, TVec3 v2, TVec3 v3)  { return crs(v2-v1, v3-v1); }
TVec3 sat(TVec3 v)                          { VEC1( sat(v[i]) ) };

bool same(TVec3*v1, TVec3*v2, float s)      { return (*v1-*v2).lng()<s; };

TVec3 min(TVec3 v1, TVec3 v2)               { VEC1( min(v1[i], v2[i]) ) };
TVec3 max(TVec3 v1, TVec3 v2)               { VEC1( max(v1[i], v2[i]) ) };
TVec3 min(TVec3 v,  float s)                { VEC1( min(v[i],s) ) };
TVec3 max(TVec3 v,  float s)                { VEC1( max(v[i],s) ) };

TVec3 reflect(TVec3 i, TVec3 n)             { return i-(n*dot(i,n)*2); }
TVec3 refract(TVec3 i, TVec3 n, float ind)  { float w,k; w=-(dot(i,n)*ind); k=1.0+(w-ind)*(w+ind);
                                              return k>-ZERO_TOLERANCE?i*ind+n*(w-sqrt(k)):reflect(i, n); }

TVec3 barycentric(TVec3* v1, TVec3* v2, TVec3* v3, float f, float g)  { return *v1 + (*v2-*v1)*f + (*v3-*v1)*g; };
float dist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)                { return crs(v-lpos,ldir).lng()/ldir.lng(); };
float projdist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)            { return dot(v-lpos,ldir); };

#undef VEC1
#undef VEC2
//---------------------------------------------------------------------------

class TMatrix4x4 {
  public:
    float m[16];
    TMatrix4x4&operator = (float s) { forExt(i, 16) m[i]=s; return *this; };
    TMatrix4x4 operator * (TMatrix4x4 mat) { TMatrix4x4 r; r=0; forExt3D(i,j,k,4,4,4) r.m[i*4+j]+=m[k*4+j]*mat.m[i*4+k]; return r; };
    TMatrix4x4&operator *=(TMatrix4x4 mat) { TMatrix4x4 r=*this; *this=0; forExt3D(i,j,k,4,4,4) m[i*4+j]+=r.m[k*4+j]*mat.m[i*4+k]; return *this; };
    TVec3 getAxisX(){ return crt(m[0], m[4], m[8]); };
    TVec3 getAxisY(){ return crt(m[1], m[5], m[9]); };
    TVec3 getAxisZ(){ return crt(m[2], m[6], m[10]); };
    TVec3 getPos()  { return crt(m[3], m[7], m[11]); };
    TVec3 transformCoord(TVec3 v) { TVec3 r=transformNormal(v); forExt(i,3)r[i]+=m[i*4+3]; return r; };
    TVec3 transformNormal(TVec3 v) { TVec3 r; r=0; forExt2D(i,j,3,3)r.v[i]+=v[j]*m[i*4+j]; return r; };
};

TMatrix4x4 matScaling(TVec3 v) { TMatrix4x4 m={v[0],0,0,0,0,v[1],0,0,0,0,v[2],0,0,0,0,1}; return m; };
TMatrix4x4 matScaling(float s) { TMatrix4x4 m={s,0,0,0,0,s,0,0,0,0,s,0,0,0,0,1}; return m; };
TMatrix4x4 matRot(float, TVec3);
TMatrix4x4 matRotX(float a) { TMatrix4x4 m={1,0,0,0,0,cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotY(float a) { TMatrix4x4 m={cos(a),0,sin(a),0,0,1,0,0,-sin(a),0,cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotZ(float a) { TMatrix4x4 m={cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matRotZXY(TVec3 v) { return matRotZ(v[2])*matRotX(v[0])*matRotY(v[1]); };
TMatrix4x4 matIdentity() { TMatrix4x4 m={1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matTranslation(TVec3 v) { TMatrix4x4 m={1,0,0,v[0],0,1,0,v[1],0,0,1,v[2],0,0,0,1}; return m; };
TMatrix4x4 transpose(TMatrix4x4 m) { TMatrix4x4 r; forExt2D(i,j,4,4)r.m[i*4+j]=m.m[j*4+i]; return r; };

Re: [Tipps & Tricks] bad programming

Verfasst: 22.10.2011, 23:09
von j.klugmann
CodingCat hat geschrieben:Wie zu allen Codebeispielen fällt mir auch zu diesem nur wieder ein: Delphi ist ganz offensichtlich die grässlichste Sprache der Welt. :P
Modernes Delphi bietet durchaus alle "modernen" Features, die man von C++ kennt und ist wesentlich angenehmer zu lesen und zu programmieren. :D

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 17:47
von hagbard
Naja also wenn es der Lesbarkeit dient verwende ich dann lieber temporäre Variablen (bei größeren Datenstrukturen meinetwegen auch als Zeiger realisiert) bevor ich mich mit den Nebeneffekten von 'with' oder Makros rumschlagen muss. Ist klar dass kann Performance kosten aber wir wissen ja "premature optimization is the root of all evil" ;)

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 19:38
von BeRsErKeR
Zudomon hat geschrieben:Es ist schade, dass es keine Defines gibt, sonst könnte man da nämlich auch damit abkürzen... in C++ hab ich damit richtig dreckig programmiert...

Erstmal schöne 1D-, 2D- und 3D-Schleifen

Code: Alles auswählen

#define forExt(i, t)              for(int (i)=0; (i)<int(t); (i)++)
#define forExt2D(i,j,t1,t2)       forExt(i, t1) forExt(j, t2)
#define forExt3D(i,j,k,t1,t2,t3)  forExt2D(i,j,t1,t2) forExt(k, t3)
Und dann daraus Vektor und Matrix Klassen bauen:

Code: Alles auswählen

#define VEC1(exp)  TVec3 r; forExt(i, 3) r.v[i]=exp; return r;
#define VEC2(exp)  forExt(i, 3) v[i]exp; return *this;

class TVec3{
  public:
    float v[3];
    TVec3&operator = (float s)   { forExt(i, 3) v[i]=s; return *this; };
    TVec3 operator - ()          { VEC1( -v[i]         ) };
    TVec3 operator - (TVec3 opp) { VEC1( v[i]-opp.v[i] ) };
    TVec3 operator - (float s)   { VEC1( v[i]-s        ) };
    TVec3 operator + (TVec3 opp) { VEC1( v[i]+opp.v[i] ) };
    TVec3 operator + (float s)   { VEC1( v[i]+s        ) };
    TVec3 operator * (float s)   { VEC1( v[i]*s        ) };
    TVec3 operator / (float s)   { DIV0( s, return operator=(0); , return operator*(1.0/s); ) };
    TVec3&operator -=(TVec3 opp) { VEC2( -=opp.v[i]    ) };
    TVec3&operator -=(float s)   { VEC2( -=s           ) };
    TVec3&operator +=(TVec3 opp) { VEC2( +=opp.v[i]    ) };
    TVec3&operator +=(float s)   { VEC2( +=s           ) };
    TVec3&operator *=(float s)   { VEC2( *=s           ) };
    TVec3&operator /=(float s)   { DIV0( s, return *this; , VEC2( /=s; ) ) };
    float&operator [](int index) { return v[index]; };
    float lngSQ()                { return sqr(v[0])+sqr(v[1])+sqr(v[2]); };
    float lng()                  { return sqrt(lngSQ()); };
    void writeTo( char *p )      { *(p++)=_Byte(v[0]); *(p++)=_Byte(v[1]); *p=_Byte(v[2]); } ;
};

TVec3 crt(float a,  float b,  float c)      { TVec3 r={a,b,c}; return r; };
float dot(TVec3 v1, TVec3 v2)               { float r=0; forExt(i,3) r+=v1[i]*v2[i]; return r; };
TVec3 crs(TVec3 v1, TVec3 v2)               { TVec3 r; forExt(i,3) r.v[i]=v1[(i+1)%3]*v2[(i+2)%3]-v1[(i+2)%3]*v2[(i+1)%3]; return r; };
TVec3 nrm(TVec3 v)                          { return v / v.lng(); }
TVec3 lrp(TVec3 v1, TVec3 v2, float s)      { TVec3 r; forExt(i,3)r.v[i]=v1[i]+s*(v2[i]-v1[i]); return r; };
TVec3 normal(TVec3 v1, TVec3 v2, TVec3 v3)  { return crs(v2-v1, v3-v1); }
TVec3 sat(TVec3 v)                          { VEC1( sat(v[i]) ) };

bool same(TVec3*v1, TVec3*v2, float s)      { return (*v1-*v2).lng()<s; };

TVec3 min(TVec3 v1, TVec3 v2)               { VEC1( min(v1[i], v2[i]) ) };
TVec3 max(TVec3 v1, TVec3 v2)               { VEC1( max(v1[i], v2[i]) ) };
TVec3 min(TVec3 v,  float s)                { VEC1( min(v[i],s) ) };
TVec3 max(TVec3 v,  float s)                { VEC1( max(v[i],s) ) };

TVec3 reflect(TVec3 i, TVec3 n)             { return i-(n*dot(i,n)*2); }
TVec3 refract(TVec3 i, TVec3 n, float ind)  { float w,k; w=-(dot(i,n)*ind); k=1.0+(w-ind)*(w+ind);
                                              return k>-ZERO_TOLERANCE?i*ind+n*(w-sqrt(k)):reflect(i, n); }

TVec3 barycentric(TVec3* v1, TVec3* v2, TVec3* v3, float f, float g)  { return *v1 + (*v2-*v1)*f + (*v3-*v1)*g; };
float dist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)                { return crs(v-lpos,ldir).lng()/ldir.lng(); };
float projdist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)            { return dot(v-lpos,ldir); };

#undef VEC1
#undef VEC2
//---------------------------------------------------------------------------

class TMatrix4x4 {
  public:
    float m[16];
    TMatrix4x4&operator = (float s) { forExt(i, 16) m[i]=s; return *this; };
    TMatrix4x4 operator * (TMatrix4x4 mat) { TMatrix4x4 r; r=0; forExt3D(i,j,k,4,4,4) r.m[i*4+j]+=m[k*4+j]*mat.m[i*4+k]; return r; };
    TMatrix4x4&operator *=(TMatrix4x4 mat) { TMatrix4x4 r=*this; *this=0; forExt3D(i,j,k,4,4,4) m[i*4+j]+=r.m[k*4+j]*mat.m[i*4+k]; return *this; };
    TVec3 getAxisX(){ return crt(m[0], m[4], m[8]); };
    TVec3 getAxisY(){ return crt(m[1], m[5], m[9]); };
    TVec3 getAxisZ(){ return crt(m[2], m[6], m[10]); };
    TVec3 getPos()  { return crt(m[3], m[7], m[11]); };
    TVec3 transformCoord(TVec3 v) { TVec3 r=transformNormal(v); forExt(i,3)r[i]+=m[i*4+3]; return r; };
    TVec3 transformNormal(TVec3 v) { TVec3 r; r=0; forExt2D(i,j,3,3)r.v[i]+=v[j]*m[i*4+j]; return r; };
};

TMatrix4x4 matScaling(TVec3 v) { TMatrix4x4 m={v[0],0,0,0,0,v[1],0,0,0,0,v[2],0,0,0,0,1}; return m; };
TMatrix4x4 matScaling(float s) { TMatrix4x4 m={s,0,0,0,0,s,0,0,0,0,s,0,0,0,0,1}; return m; };
TMatrix4x4 matRot(float, TVec3);
TMatrix4x4 matRotX(float a) { TMatrix4x4 m={1,0,0,0,0,cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotY(float a) { TMatrix4x4 m={cos(a),0,sin(a),0,0,1,0,0,-sin(a),0,cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotZ(float a) { TMatrix4x4 m={cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matRotZXY(TVec3 v) { return matRotZ(v[2])*matRotX(v[0])*matRotY(v[1]); };
TMatrix4x4 matIdentity() { TMatrix4x4 m={1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matTranslation(TVec3 v) { TMatrix4x4 m={1,0,0,v[0],0,1,0,v[1],0,0,1,v[2],0,0,0,1}; return m; };
TMatrix4x4 transpose(TMatrix4x4 m) { TMatrix4x4 r; forExt2D(i,j,4,4)r.m[i*4+j]=m.m[j*4+i]; return r; };
Dir ist ja sicherlich klar, dass das grauenhaft ist. Bei sowas finde ich etwas mehr Fleiß angebracht. Lieber ein bischen mehr Code tippen, als die komplette Übersicht zu zerstören und eventuelle Wechselwirkungen zu riskieren. Man denke nur an das schöne min/max-Problem von Windows...

Defines sind, wie schon häufig diskutiert, in 99% aller Fälle die falsche Wahl. Schreib lieber mehr Code. Von mir aus pack die for-Schleife in eine Funktion. Da mag zwar Performance-Einbusse bringen, aber die sind es auf jeden Fall wert, wenn du dadurch kryptische defines vermeiden kannst.

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 19:43
von Krishty
Besser und ohne Wiederholerei mit Templates …

Aber wie heißt es doch so schön? It was hard to write, so it should be hard to read!

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 20:22
von Zudomon
BeRsErKeR hat geschrieben:
Zudomon hat geschrieben:Es ist schade, dass es keine Defines gibt, sonst könnte man da nämlich auch damit abkürzen... in C++ hab ich damit richtig dreckig programmiert...

Erstmal schöne 1D-, 2D- und 3D-Schleifen

Code: Alles auswählen

#define forExt(i, t)              for(int (i)=0; (i)<int(t); (i)++)
#define forExt2D(i,j,t1,t2)       forExt(i, t1) forExt(j, t2)
#define forExt3D(i,j,k,t1,t2,t3)  forExt2D(i,j,t1,t2) forExt(k, t3)
Und dann daraus Vektor und Matrix Klassen bauen:

Code: Alles auswählen

#define VEC1(exp)  TVec3 r; forExt(i, 3) r.v[i]=exp; return r;
#define VEC2(exp)  forExt(i, 3) v[i]exp; return *this;

class TVec3{
  public:
    float v[3];
    TVec3&operator = (float s)   { forExt(i, 3) v[i]=s; return *this; };
    TVec3 operator - ()          { VEC1( -v[i]         ) };
    TVec3 operator - (TVec3 opp) { VEC1( v[i]-opp.v[i] ) };
    TVec3 operator - (float s)   { VEC1( v[i]-s        ) };
    TVec3 operator + (TVec3 opp) { VEC1( v[i]+opp.v[i] ) };
    TVec3 operator + (float s)   { VEC1( v[i]+s        ) };
    TVec3 operator * (float s)   { VEC1( v[i]*s        ) };
    TVec3 operator / (float s)   { DIV0( s, return operator=(0); , return operator*(1.0/s); ) };
    TVec3&operator -=(TVec3 opp) { VEC2( -=opp.v[i]    ) };
    TVec3&operator -=(float s)   { VEC2( -=s           ) };
    TVec3&operator +=(TVec3 opp) { VEC2( +=opp.v[i]    ) };
    TVec3&operator +=(float s)   { VEC2( +=s           ) };
    TVec3&operator *=(float s)   { VEC2( *=s           ) };
    TVec3&operator /=(float s)   { DIV0( s, return *this; , VEC2( /=s; ) ) };
    float&operator [](int index) { return v[index]; };
    float lngSQ()                { return sqr(v[0])+sqr(v[1])+sqr(v[2]); };
    float lng()                  { return sqrt(lngSQ()); };
    void writeTo( char *p )      { *(p++)=_Byte(v[0]); *(p++)=_Byte(v[1]); *p=_Byte(v[2]); } ;
};

TVec3 crt(float a,  float b,  float c)      { TVec3 r={a,b,c}; return r; };
float dot(TVec3 v1, TVec3 v2)               { float r=0; forExt(i,3) r+=v1[i]*v2[i]; return r; };
TVec3 crs(TVec3 v1, TVec3 v2)               { TVec3 r; forExt(i,3) r.v[i]=v1[(i+1)%3]*v2[(i+2)%3]-v1[(i+2)%3]*v2[(i+1)%3]; return r; };
TVec3 nrm(TVec3 v)                          { return v / v.lng(); }
TVec3 lrp(TVec3 v1, TVec3 v2, float s)      { TVec3 r; forExt(i,3)r.v[i]=v1[i]+s*(v2[i]-v1[i]); return r; };
TVec3 normal(TVec3 v1, TVec3 v2, TVec3 v3)  { return crs(v2-v1, v3-v1); }
TVec3 sat(TVec3 v)                          { VEC1( sat(v[i]) ) };

bool same(TVec3*v1, TVec3*v2, float s)      { return (*v1-*v2).lng()<s; };

TVec3 min(TVec3 v1, TVec3 v2)               { VEC1( min(v1[i], v2[i]) ) };
TVec3 max(TVec3 v1, TVec3 v2)               { VEC1( max(v1[i], v2[i]) ) };
TVec3 min(TVec3 v,  float s)                { VEC1( min(v[i],s) ) };
TVec3 max(TVec3 v,  float s)                { VEC1( max(v[i],s) ) };

TVec3 reflect(TVec3 i, TVec3 n)             { return i-(n*dot(i,n)*2); }
TVec3 refract(TVec3 i, TVec3 n, float ind)  { float w,k; w=-(dot(i,n)*ind); k=1.0+(w-ind)*(w+ind);
                                              return k>-ZERO_TOLERANCE?i*ind+n*(w-sqrt(k)):reflect(i, n); }

TVec3 barycentric(TVec3* v1, TVec3* v2, TVec3* v3, float f, float g)  { return *v1 + (*v2-*v1)*f + (*v3-*v1)*g; };
float dist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)                { return crs(v-lpos,ldir).lng()/ldir.lng(); };
float projdist_point_line(TVec3 v, TVec3 lpos, TVec3 ldir)            { return dot(v-lpos,ldir); };

#undef VEC1
#undef VEC2
//---------------------------------------------------------------------------

class TMatrix4x4 {
  public:
    float m[16];
    TMatrix4x4&operator = (float s) { forExt(i, 16) m[i]=s; return *this; };
    TMatrix4x4 operator * (TMatrix4x4 mat) { TMatrix4x4 r; r=0; forExt3D(i,j,k,4,4,4) r.m[i*4+j]+=m[k*4+j]*mat.m[i*4+k]; return r; };
    TMatrix4x4&operator *=(TMatrix4x4 mat) { TMatrix4x4 r=*this; *this=0; forExt3D(i,j,k,4,4,4) m[i*4+j]+=r.m[k*4+j]*mat.m[i*4+k]; return *this; };
    TVec3 getAxisX(){ return crt(m[0], m[4], m[8]); };
    TVec3 getAxisY(){ return crt(m[1], m[5], m[9]); };
    TVec3 getAxisZ(){ return crt(m[2], m[6], m[10]); };
    TVec3 getPos()  { return crt(m[3], m[7], m[11]); };
    TVec3 transformCoord(TVec3 v) { TVec3 r=transformNormal(v); forExt(i,3)r[i]+=m[i*4+3]; return r; };
    TVec3 transformNormal(TVec3 v) { TVec3 r; r=0; forExt2D(i,j,3,3)r.v[i]+=v[j]*m[i*4+j]; return r; };
};

TMatrix4x4 matScaling(TVec3 v) { TMatrix4x4 m={v[0],0,0,0,0,v[1],0,0,0,0,v[2],0,0,0,0,1}; return m; };
TMatrix4x4 matScaling(float s) { TMatrix4x4 m={s,0,0,0,0,s,0,0,0,0,s,0,0,0,0,1}; return m; };
TMatrix4x4 matRot(float, TVec3);
TMatrix4x4 matRotX(float a) { TMatrix4x4 m={1,0,0,0,0,cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotY(float a) { TMatrix4x4 m={cos(a),0,sin(a),0,0,1,0,0,-sin(a),0,cos(a),0,0,0,0,1}; return m; };
TMatrix4x4 matRotZ(float a) { TMatrix4x4 m={cos(a),-sin(a),0,0,sin(a),cos(a),0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matRotZXY(TVec3 v) { return matRotZ(v[2])*matRotX(v[0])*matRotY(v[1]); };
TMatrix4x4 matIdentity() { TMatrix4x4 m={1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; return m; };
TMatrix4x4 matTranslation(TVec3 v) { TMatrix4x4 m={1,0,0,v[0],0,1,0,v[1],0,0,1,v[2],0,0,0,1}; return m; };
TMatrix4x4 transpose(TMatrix4x4 m) { TMatrix4x4 r; forExt2D(i,j,4,4)r.m[i*4+j]=m.m[j*4+i]; return r; };
Dir ist ja sicherlich klar, dass das grauenhaft ist. Bei sowas finde ich etwas mehr Fleiß angebracht. Lieber ein bischen mehr Code tippen, als die komplette Übersicht zu zerstören und eventuelle Wechselwirkungen zu riskieren. Man denke nur an das schöne min/max-Problem von Windows...

Defines sind, wie schon häufig diskutiert, in 99% aller Fälle die falsche Wahl. Schreib lieber mehr Code. Von mir aus pack die for-Schleife in eine Funktion. Da mag zwar Performance-Einbusse bringen, aber die sind es auf jeden Fall wert, wenn du dadurch kryptische defines vermeiden kannst.
Naja, könnt ihr sehen wir ihr wollt... zum Beispiel hat mir Marc (zzador hier im Forum) als ich ihm den Post gezeigt habe im ICQ dazu folgendes geschrieben:
(23:21:24) Marc: Die Makros sind schonmal sehr nett
(23:22:19) Marc: Da haste aber extrem gefeilt
(23:24:14) Marc: Das ist hardcore-Democoding code würd ich fast sagen
(23:24:42) Marc: Das ist sogar der Source-Code optimiert :-D:-D:-D
(23:26:36) Marc: Haste die Funktionalität der Klasse mit nem C++ Compiler auch überprüft?
(23:27:44) Marc: Pervers...echt...respekt
(23:28:13) Marc: Wär mir persönlich nie gekommen den Preprozessor so derbe auszunutzen
(23:28:47) Marc: Dadurch wird die ganze Klasse extrem leserlich und kompakt
(23:29:13) Marc: Code-Technisch muss ich das als echtes Meisterwerk sehen
(23:36:26) Zudomon: sorry, war gerade essen
(23:36:51) Zudomon: Die Klassen funktionieren, das war so im Softwareengineering bei uns
(23:37:00) Zudomon: da hatte ich ja den part des raytracers geschrieben
(23:37:27) Zudomon: Danke! Wäre mal geil, wenn da mal in dem Thread jemand verteidigt... :D
(23:37:41) Marc: das mit den Defines?
(23:37:48) Marc: Ist übelst Elite find ich
Er sagt es, die Klassen werden leserlich und kompakt... das ist genau das, was ich brauche... wenn der code tausende Zeilen hat, dann blick ich nicht durch.

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 20:36
von zzador
Also ich muss sagen, daß ich die Klasse wirklich gelungen finde. Programmiere C/C++ jetzt schon über 10 Jahre, aber den Preprozessor auf diese Art auszunutzen, auf die Idee bin ich noch nicht gekommen. Netter tipp...durch den Preprozessor wird sich oft widerholender Code eingespart, ohne gleich inline-methoden verwenden zu müssen. Was das Kommentar bzgl. der Templates angeht, wüsste ich jetzt nicht, wo in Zudomon's Beispiel Templates angebracht wären. Zudomon benutzt den Preprozessor um vor dem Kompilieren praktisch per automatischem Copy&Paste seine Code-Fragmente einzufügen. Er benutzt nirgends eine Klassen-Eigenschaft, dessen Daten-Typ erst zur Umsetzungszeit bekannt ist, also ist mir nicht ganz klar, wo sich Templates da als eleganter erweisen sollen. Ich habe solche Vektor-Klassen jetzt schon mehr als einmal geschrieben und kann daher sagen, daß Zudomons Version deutlich kompakter als meine Version ist, aber dennoch nicht weniger leserlich. Ich denke, ich werde in Zukunft den Preprozessor auch etwas intensiver nutzen.

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 20:48
von eXile
[youtube]gvdf5n-zI14[/youtube]

Re: [Tipps & Tricks] bad programming

Verfasst: 23.10.2011, 20:50
von Krishty
zzador hat geschrieben:Er benutzt nirgends eine Klassen-Eigenschaft, dessen Daten-Typ erst zur Umsetzungszeit bekannt ist, also ist mir nicht ganz klar, wo sich Templates da als eleganter erweisen sollen.
Die gesamte Vektorklasse ist die Realisierung des Konzepts, arithmetische Operatoren zu implementieren, mit einem spezifischen Datentyp. Und dieser Datentyp ist wiederum die Realisierung des Konzepts eines Arrays, auf das jede Operation parallel angewandt wird, mit einem bestimmten Datentyp und einer bestimmten Breite.

Kurz: += und *= durch for_each implementieren (zugegeben – eine Überladung für zwei Arrays wird man brauchen; vielleicht sind aber auch nur meine Lambda-Kenntnisse zu begrenzt), -= und /= als Inverse davon definieren, damit Arithmetic<> instanzieren und der Vektor ist dank zwei Templates fertig.

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 03:40
von dot
zzador hat geschrieben:Netter tipp...durch den Preprozessor wird sich oft widerholender Code eingespart, ohne gleich inline-methoden verwenden zu müssen.
Ich hoffe doch mal das war Ironie!?

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 11:09
von antisteo
dot hat geschrieben:
zzador hat geschrieben:Netter tipp...durch den Preprozessor wird sich oft widerholender Code eingespart, ohne gleich inline-methoden verwenden zu müssen.
Ich hoffe doch mal das war Ironie!?
Also ich finde die Klasse auch ganz nett.

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 15:15
von CodingCat
antisteo hat geschrieben:
dot hat geschrieben:
zzador hat geschrieben:Netter tipp...durch den Preprozessor wird sich oft widerholender Code eingespart, ohne gleich inline-methoden verwenden zu müssen.
Ich hoffe doch mal das war Ironie!?
Also ich finde die Klasse auch ganz nett.
Ich kann euch auch nur raten, die Finger von solchem Blödsinn zu lassen. Templates und inline-Methoden sind genau dafür da, Code-Generierung einigermaßen verständlich, berechenbar und (Typ-)sicher zu gestalten. Die hier gerade diskutierte Makromagie erfüllt keine dieser Eigenschaften.

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 15:42
von kaiserludi
CodingCat hat geschrieben:
antisteo hat geschrieben:
dot hat geschrieben:
zzador hat geschrieben:Netter tipp...durch den Preprozessor wird sich oft widerholender Code eingespart, ohne gleich inline-methoden verwenden zu müssen.
Ich hoffe doch mal das war Ironie!?
Also ich finde die Klasse auch ganz nett.
Ich kann euch auch nur raten, die Finger von solchem Blödsinn zu lassen. Templates und inline-Methoden sind genau dafür da, Code-Generierung einigermaßen verständlich, berechenbar und (Typ-)sicher zu gestalten. Die hier gerade diskutierte Makromagie erfüllt keine dieser Eigenschaften.
Eben: Durch Inline Methoden wird sich oft widerholender Code eingespart, ohne gleich Makros mitsamt ihrer Nachteile verwenden zu müssen, nicht umgekehrt!

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 20:45
von zzador
Die gesamte Vektorklasse ist die Realisierung des Konzepts, arithmetische Operatoren zu implementieren, mit einem spezifischen Datentyp. Und dieser Datentyp ist wiederum die Realisierung des Konzepts eines Arrays, auf das jede Operation parallel angewandt wird, mit einem bestimmten Datentyp und einer bestimmten Breite.
Also dadurch hättest Du dann 2 Klassen...Vector<Array> und dein Array, welches die Arithmetischen Operatoren implementiert. 2 Klassen erklären sich wesentlich schwerer von selbst als eine kompakte Klasse wie die von Zudomon.
Ich hoffe doch mal das war Ironie!?
Nein, war es nicht. Ich bin mir auch dadrüber im Klaren, was Inline-Methoden sind, da ich sie ebenfalls sehr oft benutze. Sie sind nichts anderes als Preprozessor-Makros auf Code-Ebene. Im Gegensatz zu Makros müssen sie allerdings in der Klasse definiert, oder zumindest deklariert werden und würden hier in dem Fall von Zudomon die Kompaktheit seiner Klasse negativ beeinträchtigen, oder um es anders zu formulieren: Sie würden ablenken

Und genau das ist der Knackpunkt. Es ging mir von vorne rein um die extreme lesbarkeit von Zudomon's Klasse. Ihre gesamte Funktionalität erklärt sich praktisch von selbst beim betrachten der Klasse, ohne die Dokumentation oder Kommentare zu Rate ziehen zu müssen. Was ich damit sagen will ist, dass man die Funktionalität des Preprozessors ruhig ausnutzen soll, wenn es die Lesbarkeit steigert.

Re: [Tipps & Tricks] bad programming

Verfasst: 24.10.2011, 21:08
von kaiserludi
zzador hat geschrieben:
Die gesamte Vektorklasse ist die Realisierung des Konzepts, arithmetische Operatoren zu implementieren, mit einem spezifischen Datentyp. Und dieser Datentyp ist wiederum die Realisierung des Konzepts eines Arrays, auf das jede Operation parallel angewandt wird, mit einem bestimmten Datentyp und einer bestimmten Breite.
Also dadurch hättest Du dann 2 Klassen...Vector<Array> und dein Array, welches die Arithmetischen Operatoren implementiert. 2 Klassen erklären sich wesentlich schwerer von selbst als eine kompakte Klasse wie die von Zudomon.
Ich hoffe doch mal das war Ironie!?
Nein, war es nicht. Ich bin mir auch dadrüber im Klaren, was Inline-Methoden sind, da ich sie ebenfalls sehr oft benutze. Sie sind nichts anderes als Preprozessor-Makros auf Code-Ebene. Im Gegensatz zu Makros müssen sie allerdings in der Klasse definiert, oder zumindest deklariert werden und würden hier in dem Fall von Zudomon die Kompaktheit seiner Klasse negativ beeinträchtigen, oder um es anders zu formulieren: Sie würden ablenken

Und genau das ist der Knackpunkt. Es ging mir von vorne rein um die extreme lesbarkeit von Zudomon's Klasse. Ihre gesamte Funktionalität erklärt sich praktisch von selbst beim betrachten der Klasse, ohne die Dokumentation oder Kommentare zu Rate ziehen zu müssen. Was ich damit sagen will ist, dass man die Funktionalität des Preprozessors ruhig ausnutzen soll, wenn es die Lesbarkeit steigert.
1.
Nein, ein Vector<Array> wäre ja ein Vektor mit lauter Elementen vom Typ Array, Krishty meint aber einen Vektor, der mit Hilfe eines Arrays implementiert wurde. Der Array ist ein Implementierungsdetail, der den Nutzer der Vektorklasse normalerweise gar nicht interessiert.

2.
Nein, offensichtlich bist du dir nicht darüber im Klaren, was inline-Methoden sind oder was Makros sind.
Versuch mal Includeguards wie

Code: Alles auswählen

#ifndef FOO_H
#define FOO_H

// headercode

#endif
mit einer Inlinemethode umzusetzen

oder Checks auf Compilerdefines wie

Code: Alles auswählen

	#ifdef __cplusplus
		extern "C"
		{
	#endif

		// imagine some function declarations here

	#ifdef __cplusplus
		}
	#endif
Das sollte offensichtlich machen, dass Inlinemethoden eben nicht einfach Präprozessormakros auf Compilerebene sind.

Wer schon mal ein 100 Zeilen-Makro debugen durfte, weiß, wie gut der Debugger damit klar kommt, da durch zu steppen.
Und sowas wie

Code: Alles auswählen

#define sum(a, b) a+b
result = sum(5, 5)*5; // looks like result is (5+5)*5==50, but due to the missing "()" in the macro it is 5+5*5==30
kann einem mit inline-methods nicht passieren (die in der Praxis vorkommenden Fälle solcher Bugs sind meist weit weniger offensichtlich zu finden, als es in diesem simplen Beispiel der Fall ist)

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 00:35
von dot
Wer immer Makros für eine tolle Idee hält, den bitte ich, folgenden Code zu kompilieren:

Code: Alles auswählen

#include <windows.h>
#include <iostream>
#include <algorithm>

int main()
{
  int a, b;
  std::cin >> a >> b;
  std::cou << "max(a, b) = " << std::max(a, b);
}

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 00:57
von kaiserludi
dot hat geschrieben:Wer immer Makros für eine tolle Idee hält, den bitte ich, folgenden Code zu kompilieren:

Code: Alles auswählen

#include <windows.h>
#include <iostream>
#include <algorithm>

int main()
{
  int a, b;
  std::cin >> a >> b;
  std::cou << "max(a, b) = " << std::max(a, b);
}
Wenn, dann so:

Code: Alles auswählen

#include <windows.h>
#include <iostream>
#include <algorithm>

int main()
{
  int a, b;
  std::cin >> a >> b;
  std::cout << "max(a, b) = " << max(a, b);
}
Dann kompiliert das auch.
Was du uns mit dem Code nun sagen willst, ist mir aber nicht klar. Der Code macht doch genau das, was er soll?

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 01:05
von dot
Nicht wenn das std:: dort steht und eben genau das ist der Punkt, denn eigentlich sollte es kompilieren. Nun ist die Frage warum es das nicht tut...

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 01:32
von kaiserludi
dot hat geschrieben:Nicht wenn das std:: dort steht und eben genau das ist der Punkt, denn eigentlich sollte es kompilieren. Nun ist die Frage warum es das nicht tut...
Dort steht nirgends, dass max laut Standard zum namespace stl gehört, nur dass es zu den stl-Algorithmen gehört, was nicht ausschließt, dass es im globalen Namespace liegen kann.

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 01:36
von CodingCat
Ich kenn noch einen, ich kenn noch einen! *hüpf, hüpf*

Code: Alles auswählen

#include <windows.h>
#include <iostream>

int main()
{
  int near, far;
  std::cin >> near >> far;
  std::cout << "near = " << near << "; far = " << far;
}
OK, ganz leicht am Thema Geltungsbereiche vorbei ... :P


kaiserludi: Der Punkt ist, du kannst ohne #undef den STL-Algorithmus max() nicht mehr nutzen, selbst wenn du wolltest. ;-)

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 01:38
von dot
kaiserludi hat geschrieben:Dort steht nirgends, dass max laut Standard zum namespace stl gehört, nur dass es zu den stl-Algorithmen gehört, was nicht ausschließt, dass es im globalen Namespace liegen kann.
Natürlich liegt max() im namespace std. Das steht nicht explizit dort weil es sich von selbst versteht. Aber bitteschön:
ISO/IEC 14882:2011 §25.1 hat geschrieben:

Code: Alles auswählen

namespace std {
  ...
  template<class T> const T& max(const T& a, const T& b);
  ...
}
CodingCat hat geschrieben:kaiserludi: Der Punkt ist, du kannst ohne #undef den STL-Algorithmus max() nicht mehr nutzen, selbst wenn du wolltest. ;-)
Na toll, jetzt hast dus gespoiled :P
Denn vor allem muss man überhaupt erstmal draufkommen was der Fehler ist. Die Meldungen die man da bekommt, sind normalerweise alles andre als hilfreich.
Man muss nurmal googlen wieviele Leute ständig in irgendwelchen Foren völlig verzweifelt um Hilfe rufen, weil sie am Ende ihrer Kräfte sind und einfach absolut nicht draufkommen, woher diese komische Linkerfehler kommen, sobald sie die GetMessage() Methode ihrer neuen, supertollen, lockfree MessageQueue Klasse aufrufen wollen. Es macht einfach keinen Sinn, der Code sieht völlig korrekt aus und vor allem: Warum sucht der Linker nach einer ?GetMessageW@MessageQueue@mystuff@@QAEXXZ!? :shock: Tja, Makros bei der Arbeit ;)
Und die Moral von der Geschicht': Makros verwend' man nicht. Außer für bedingte Kompilierung und andere Dinge, wo Makros eben gebraucht werden. Auf gar keinen Fall jedoch, anstatt einer Funktion.

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 02:06
von kaiserludi
Jetzt würde mich aber interessieren, warum er das max im std-namespace nicht findet, wenn es ein globales max-define gibt?
Gehe ich korrekt in der Annahme, dass der Präprozessor als reiner Textersetzer aus std::max(a, b) dann std::((a<b)?b:a) macht, was der Compiler dann natürlich nicht versteht?

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 02:08
von dot
kaiserludi hat geschrieben:Gehe ich korrekt in der Annahme, dass der Präprozessor als reiner Textersetzer aus std::max(a, b) dann std::((a<b)?b:a) macht, was der Compiler dann natürlich nicht versteht?
Exakt. Und der Programmierer versteht die daraus resultierenden Fehlermeldungen in der Regel noch weniger...

Re: [Tipps & Tricks] bad programming

Verfasst: 25.10.2011, 02:16
von kaiserludi
dot hat geschrieben:
kaiserludi hat geschrieben:Gehe ich korrekt in der Annahme, dass der Präprozessor als reiner Textersetzer aus std::max(a, b) dann std::((a<b)?b:a) macht, was der Compiler dann natürlich nicht versteht?
Exakt. Und der Programmierer versteht die daraus resultierenden Fehlermeldungen in der Regel noch weniger...
Was lernen wir daraus: MAKROS immer in ALL_UPPERCASE, wenn sie unbedingt sein müssen, alles andere eben nicht in in der Weise deklarieren, dann ist das Risiko solcher Fehlerquellen schon einmal massiv gesenkt.
Ändert natürlich nichts daran, dass eine globale inline-Funktion max() das Problem nicht produziert hätte.