From c23d118a68ca033e1753fd9efa5a5c37ff4637ee Mon Sep 17 00:00:00 2001 From: cbaakman Date: Sat, 15 Aug 2015 14:26:08 +0200 Subject: [PATCH 01/10] Some more comments --- src/account.cpp | 113 +++++++++++++++++++++++++--------------- src/account.h | 11 +++- src/manager/manager.cpp | 23 ++++++-- src/str.h | 29 ++++++++++- 4 files changed, 127 insertions(+), 49 deletions(-) diff --git a/src/account.cpp b/src/account.cpp index 0b7d346..d1f08cf 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -26,11 +26,17 @@ #include "account.h" #include "str.h" +#include "err.h" #include #define HASHSTRING_LENGTH 20 void getHash(const char* username, const char* password, unsigned char* hash) { + /* + This function is used for checking passwords. + If it changes, all account files must be created anew. + */ + SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx,(void*)username,strlen(username)); @@ -41,14 +47,9 @@ void getHash(const char* username, const char* password, unsigned char* hash) void AccountFileName (const char *directory, const char *username, char *out) { - sprintf(out,"%s%c%s.account", directory, PATH_SEPARATOR, username); -} + // .account -std::string accountError; - -const char *GetAccountError () -{ - return accountError.c_str(); + sprintf(out,"%s%c%s.account", directory, PATH_SEPARATOR, username); } #define LINEID_ACCOUNT "ACCOUNT" @@ -59,30 +60,40 @@ bool MakeAccount (const char* dirPath, const char* username, const char* passwor _password[PASSWORD_MAXLENGTH]; unsigned char hash[HASHSTRING_LENGTH]; + /* + username is case insensitive, thus always converted to lowercase + password is case sensitive + */ int i; - for(i=0;username[i];i++) + for (i=0;username[i];i++) _username[i]=tolower(username[i]); _username[i]=NULL; - for(i=0;password[i];i++) - _password[i]=tolower(password[i]); - _password[i]=NULL; + strcpy (_password, password); + + // Open the account file AccountFileName (dirPath, _username, filepath); - FILE* f=fopen (filepath, "wb"); - if(!f) + FILE* f = fopen (filepath, "wb"); + if (!f) { - accountError = std::string("cannot open output file ") + filepath + ": " + strerror(errno); + std::string _errorstring = std::string ("cannot open output file ") + filepath + ": " + strerror (errno); + SetError (_errorstring.c_str ()); return false; } - getHash(_username, _password, hash); - fprintf(f,"%s %s ",LINEID_ACCOUNT,_username); + /* + Write a single line, including + the username and password hash. + */ + + getHash (_username, _password, hash); + fprintf (f, "%s %s ", LINEID_ACCOUNT, _username); // write each hash byte - for(i=0; i #include #include "../str.h" +#include "../err.h" void PromptUsername (char *username, const int maxLength) { @@ -40,6 +41,12 @@ void PromptUsername (char *username, const int maxLength) } void PromptPassword (char *password, const int maxLength) { + /* + Password prompt should be masked input: ******* + + That's the reason why ncurses is used. + */ + int i = 0; unsigned char ch = 0; @@ -100,7 +107,8 @@ void OnMakeAccount (const std::string &exe_dir) } } } - while(usernameError); + // Is username correct syntax? Else reloop. + while (usernameError); PromptPassword (password, PASSWORD_MAXLENGTH); @@ -111,21 +119,26 @@ void OnMakeAccount (const std::string &exe_dir) } else { - printw ("%s\n", GetAccountError ()); + printw ("%s\n", GetError ()); } } bool OnCommand(const char* cmd, const std::string &exe_dir) { + // Execute command 'cmd', given by user + if (strcmp (cmd, "quit") == 0) { + // stop looping return false; } else if (strcmp (cmd, "make-account")==0) { OnMakeAccount (exe_dir); } - else if (emptyline (cmd) || strcmp (cmd,"help") == 0) + else if (emptyline (cmd) || strcmp (cmd, "help") == 0) { + // If an empty line was entered, print help: + printw ("quit: exit application\n"); printw ("make-account: create new account file\n"); printw ("help: print this info\n"); @@ -151,12 +164,14 @@ int main (int argc, char** argv) bool running = true; while (running) { + // print commandline prompt: printw ("manager>"); + // Get the command and remove trailing whitespaces: getnstr (cmd, cmdlen); stripr (cmd); - // take input commands + // execute command running = OnCommand(cmd, exe_dir); } diff --git a/src/str.h b/src/str.h index fc498db..23bd059 100644 --- a/src/str.h +++ b/src/str.h @@ -24,6 +24,12 @@ #include #include +/* + Here, the PATH_SEPARATOR macro is used + to join paths. Could also use boost for this: + + http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/reference.html + */ #ifdef _WIN32 #define PATH_SEPARATOR '\\' #else @@ -32,14 +38,35 @@ bool isnewline (const int c); bool emptyline (const char *line); + +/** + * Places a NULL character so that trailing whitespaces + * are removed. + */ void stripr (char *s); -const char *ParseFloat(const char *in, float *out); // not locale dependent +/** + * atof and scanf are locale dependent. ParseFloat isn't, + * decimals always assumed to have dots here, never commas. + * + * :returns: the string after the parsed number on success, + * NULL on failure. + */ +const char *ParseFloat(const char *in, float *out); +/** + * Like strcmp, but ignores case. + */ int StrCaseCompare(const char *s1, const char *s2); +/** + * splits a string by given character. + */ void split (const char *s, const char by, std::list &out); +/** + * Gives the start and end position of the word at pos in the string. + */ void WordAt (const char *s, const int pos, int &start, int &end); #endif // STR_H From f67545e961528710aa24786f36113f0083c12c53 Mon Sep 17 00:00:00 2001 From: cbaakman Date: Sat, 15 Aug 2015 14:26:59 +0200 Subject: [PATCH 02/10] BUGFIX: server and manager need err.cpp now --- manager.cbp | 2 ++ server.cbp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/manager.cbp b/manager.cbp index 00be3df..3727dda 100644 --- a/manager.cbp +++ b/manager.cbp @@ -31,6 +31,8 @@ + + diff --git a/server.cbp b/server.cbp index 4784533..223e3ad 100644 --- a/server.cbp +++ b/server.cbp @@ -41,6 +41,8 @@ + + From 3666f35b20093041785ca9b7091dc1d00e75e318 Mon Sep 17 00:00:00 2001 From: cbaakman Date: Sat, 15 Aug 2015 23:39:05 +0200 Subject: [PATCH 03/10] Some more comments --- src/matrix.h | 40 +++++++++++++++++++++++++++------------- src/quat.h | 10 +++++++++- src/random.cpp | 2 ++ src/str.cpp | 41 +++++++++++++++++++++++++++++++---------- src/test3d/toon.cpp | 19 +++++++++++++++---- src/vec.h | 21 ++++++++++++--------- 6 files changed, 96 insertions(+), 37 deletions(-) diff --git a/src/matrix.h b/src/matrix.h index 6e8e99f..394b732 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -170,6 +170,9 @@ inline matrix4 matID() return m; } +/* + Careful, Matrices with determinant 0 are not invertible! + */ inline matrix4 matInverse(const matrix4 &m) { float @@ -229,6 +232,7 @@ inline matrix4 matInverse(const matrix4 &m) return kInv; } +// The transpose is flipped along the diagonal inline matrix4 matTranspose (const matrix4 &m) { matrix4 t; @@ -240,7 +244,7 @@ inline matrix4 matTranspose (const matrix4 &m) return t; } -inline matrix4 matRotX( const float angle )// radians +inline matrix4 matRotX( const float angle ) // radians { matrix4 m; const float c=cos(angle); @@ -253,7 +257,7 @@ inline matrix4 matRotX( const float angle )// radians return m; } -inline matrix4 matRotY( const float angle )// radians +inline matrix4 matRotY( const float angle ) // radians { matrix4 m; const float c=cos(angle); @@ -266,7 +270,7 @@ inline matrix4 matRotY( const float angle )// radians return m; } -inline matrix4 matRotZ( const float angle )// radians +inline matrix4 matRotZ( const float angle ) // radians { matrix4 m; const float c=cos(angle); @@ -279,7 +283,7 @@ inline matrix4 matRotZ( const float angle )// radians return m; } -inline matrix4 matQuat(const Quaternion &q) +inline matrix4 matQuat (const Quaternion &q) // also a rotation matrix { float f = 2.0f / q.Length(); @@ -295,7 +299,7 @@ inline matrix4 matQuat(const Quaternion &q) return m; } -inline matrix4 matRotAxis(const vec3& axis, float angle)// radians +inline matrix4 matRotAxis (const vec3& axis, float angle) // radians { matrix4 m; vec3 a=axis.Unit(); @@ -316,7 +320,7 @@ inline matrix4 matRotAxis(const vec3& axis, float angle)// radians return m; } -inline matrix4 matScale(const float x,const float y,const float z) +inline matrix4 matScale (const float x, const float y, const float z) { matrix4 m; @@ -327,7 +331,7 @@ inline matrix4 matScale(const float x,const float y,const float z) return m; } -inline matrix4 matTranslation( const float x, const float y, const float z ) +inline matrix4 matTranslation (const float x, const float y, const float z) { matrix4 m; @@ -338,7 +342,7 @@ inline matrix4 matTranslation( const float x, const float y, const float z ) return m; } -inline matrix4 matTranslation( const vec3& v ) +inline matrix4 matTranslation (const vec3& v) { matrix4 m; @@ -349,8 +353,12 @@ inline matrix4 matTranslation( const vec3& v ) return m; } -inline matrix4 matLookAt( const vec3& eye, const vec3& lookat, const vec3& up ) +inline matrix4 matLookAt (const vec3& eye, const vec3& lookat, const vec3& up) { + /* + Useful for camera positions. + */ + vec3 _right, _up, _forward; matrix4 m; @@ -366,8 +374,11 @@ inline matrix4 matLookAt( const vec3& eye, const vec3& lookat, const vec3& up ) return m; } -// "matSkew" requires a plane normal and plane d input. -inline matrix4 matSkew( const vec3 n/*normalized*/, float d ) +/* + "matSkew" requires a plane normal and plane d input. + The normal (n) is assumed to have length 1.0 + */ +inline matrix4 matSkew (const vec3 n, float d) { matrix4 m; // distance=p*n+d @@ -394,7 +405,9 @@ inline matrix4 matSkew( const vec3 n/*normalized*/, float d ) return m; } -inline matrix4 matPerspec(float view_angle,float aspect_ratio,float near_viewdist,float far_viewdist) + +// Perspective projection matrix. Z-axis points into the screen. +inline matrix4 matPerspec (float view_angle, float aspect_ratio, float near_viewdist, float far_viewdist) { float a=0.5f*view_angle; float f=1.0f/tan(a); @@ -411,7 +424,8 @@ inline matrix4 matPerspec(float view_angle,float aspect_ratio,float near_viewdis return m; } -inline matrix4 matOrtho(float leftX, float rightX, float upY, float downY, float nearZ, float farZ) +// Orthographic projection matrix. Arguments define screen boundaries. +inline matrix4 matOrtho (float leftX, float rightX, float upY, float downY, float nearZ, float farZ) { float Xdiff = rightX - leftX, Ydiff = upY - downY, diff --git a/src/quat.h b/src/quat.h index 9a65c59..042a36b 100644 --- a/src/quat.h +++ b/src/quat.h @@ -25,6 +25,14 @@ #define QUAT_ID Quaternion(0,0,0,1) +/* + Quaternions are used to represent rotation. + + For further info, see: + https://en.wikipedia.org/wiki/Quaternion + https://en.wikipedia.org/wiki/Slerp + */ + struct Quaternion { union { @@ -57,7 +65,7 @@ struct Quaternion { return length2; } - float Length () const + float Length () const { return sqrt (Length2()); } diff --git a/src/random.cpp b/src/random.cpp index c9891ef..7de19b9 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -33,5 +33,7 @@ float RandomFloat(float _min, float _max) int n = 10000; float f = float(rand() % n) / n; + // f is a random number between 0.0f and 1.0f + return _min + f * (_max - _min); } diff --git a/src/str.cpp b/src/str.cpp index 89c9124..02f9014 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -29,48 +29,64 @@ const char *ParseFloat(const char *in, float *out) { float f = 10.0f; int digit, ndigit = 0; + + // start from zero *out = 0; + const char *p = in; while (*p) { - if (isdigit(*p)) + if (isdigit (*p)) { digit = (*p - '0'); - if (f > 1.0f) + + if (f > 1.0f) // left from period { *out *= f; *out += digit; } - else + else // right from period, decimal { *out += f * digit; f *= 0.1f; } ndigit++; } - else if (tolower(*p) == 'e') + else if (tolower (*p) == 'e') { + // exponent + + // if no digits precede the exponent, assume 1 if (ndigit <= 0) *out = 1.0f; p++; - if (*p == '+') - p++; + if (*p == '+') // '+' just means positive power, default + p++; // skip it, don't give it to atoi int e = atoi (p); *out = *out * pow(10, e); - if (*p == '-') p++; - while (isdigit(*p)) p++; + // read past exponent number + if (*p == '-') + p++; + + while (isdigit(*p)) + p++; + return p; } else if (*p == '.') { + // expect decimal digits after this + f = 0.1f; } else if (*p == '-') { + // negative number + float v; p = ParseFloat(p + 1, &v); @@ -80,6 +96,8 @@ const char *ParseFloat(const char *in, float *out) } else { + // To assume success, must have read at least one digit + if (ndigit > 0) return p; else @@ -90,9 +108,9 @@ const char *ParseFloat(const char *in, float *out) return p; } -bool isnewline(const int c) +bool isnewline (const int c) { - return (c=='\n'||c=='\r'); + return (c=='\n' || c=='\r'); } bool emptyline (const char *line) { @@ -100,12 +118,15 @@ bool emptyline (const char *line) { if (!isspace (*line)) return false; + line ++; } return true; } void stripr (char *s) { + // Start on the back and move left: + int n = strlen (s); while (true) { diff --git a/src/test3d/toon.cpp b/src/test3d/toon.cpp index cb205fb..ee2b838 100644 --- a/src/test3d/toon.cpp +++ b/src/test3d/toon.cpp @@ -49,10 +49,11 @@ bool ToonScene::Init () bool success; xmlDocPtr pDoc; + // Load head mesh: f = SDL_RWFromZipArchive (resPath.c_str(), "head.xml"); if (!f) return false; - pDoc = ParseXML(f); + pDoc = ParseXML (f); f->close(f); if (!pDoc) @@ -61,7 +62,8 @@ bool ToonScene::Init () return false; } - success = ParseMesh(pDoc, &meshDataHead); + // Convert xml to mesh: + success = ParseMesh (pDoc, &meshDataHead); xmlFreeDoc (pDoc); if (!success) @@ -70,6 +72,7 @@ bool ToonScene::Init () return false; } + // Load background image: f = SDL_RWFromZipArchive (resPath.c_str(), "toonbg.png"); if (!f) return false; @@ -82,6 +85,7 @@ bool ToonScene::Init () return false; } + // Load the vertex shader source: f = SDL_RWFromZipArchive (resPath.c_str(), "shaders/toon.vsh"); if (!f) return false; @@ -95,6 +99,7 @@ bool ToonScene::Init () return false; } + // Load the fragment shader source: f = SDL_RWFromZipArchive (resPath.c_str(), "shaders/toon.fsh"); if (!f) return false; @@ -107,6 +112,7 @@ bool ToonScene::Init () return false; } + // Create shader from sources: shaderProgram = CreateShaderProgram (sourceV, sourceF); if (!shaderProgram) { @@ -118,6 +124,11 @@ bool ToonScene::Init () } void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, const GLfloat howmuch) { + /* + Almost the same as a normal mesh rendering, + except that the vertices are moved along their normals. + */ + if(pMeshData->subsets.find(id) == pMeshData->subsets.end()) { SetError ("cannot render %s, no such subset", id.c_str()); @@ -129,7 +140,7 @@ void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, const vec3 *n; vec3 p; - for (std::list::const_iterator it = pSubset->quads.begin(); it != pSubset->quads.end(); it++) + for (std::list ::const_iterator it = pSubset->quads.begin(); it != pSubset->quads.end(); it++) { glBegin(GL_QUADS); @@ -149,7 +160,7 @@ void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, } glBegin(GL_TRIANGLES); - for (std::list::const_iterator it = pSubset->triangles.begin(); it != pSubset->triangles.end(); it++) + for (std::list ::const_iterator it = pSubset->triangles.begin(); it != pSubset->triangles.end(); it++) { PMeshTriangle pTri = *it; for (size_t j = 0; j < 3; j++) diff --git a/src/vec.h b/src/vec.h index 22466da..d47f103 100644 --- a/src/vec.h +++ b/src/vec.h @@ -34,7 +34,6 @@ #define PI 3.1415926535897932384626433832795 - struct vec3 { union { @@ -44,9 +43,9 @@ struct vec3 float v[3]; }; - vec3(){} - vec3(float _x,float _y,float _z){ x=_x; y=_y; z=_z; } - vec3(const vec3 &v) + vec3 (){} + vec3 (float _x,float _y,float _z){ x=_x; y=_y; z=_z; } + vec3 (const vec3 &v) { x = v.x; y = v.y; @@ -59,7 +58,9 @@ struct vec3 vec3 Unit() const { - float l=Length(); + // The unit vector has length 1.0 + + float l = Length(); if(l>0) return ((*this)/l); else return *this; } @@ -120,8 +121,10 @@ inline vec3 ClosestPointOnLine(const vec3& l1,const vec3& l2,const vec3& point) struct Plane { - vec3 n; - float d; + vec3 n; // plane normal, should have length 1.0 + float d; // shortest distance from (0,0,0) to plane + + // n * d is a point on the plane }; inline Plane Flip (const Plane &plane) @@ -146,7 +149,7 @@ struct Triangle { p[2] = p2; } - vec3 Center() const + vec3 Center () const { vec3 pb = 0.5f * (p[1] - p[0]), pz = pb + 0.333333f*(p[2] - pb); @@ -154,7 +157,7 @@ struct Triangle { return pz; } - Plane GetPlane() const + Plane GetPlane () const { Plane plane; plane.n = Cross(p[1] - p[0], p[2] - p[0]).Unit(); From 5c3ec8af1fc3c16429edc807dfb1e29ab1faa02f Mon Sep 17 00:00:00 2001 From: cbaakman Date: Sun, 16 Aug 2015 15:47:26 +0200 Subject: [PATCH 04/10] Some more comments --- src/geo2d.cpp | 51 +++-- src/geo2d.h | 96 ++++++--- src/ip.h | 20 +- src/server/server.cpp | 126 +++++++----- src/server/server.h | 66 +++--- src/shader.cpp | 55 +++-- src/shader.h | 6 + src/test3d/collision.cpp | 429 ++++++++++----------------------------- src/test3d/hub.cpp | 34 +++- src/test3d/hub.h | 11 + src/test3d/toon.cpp | 18 +- src/test3d/toon.h | 5 +- src/util.cpp | 20 +- src/vec.h | 15 +- 14 files changed, 449 insertions(+), 503 deletions(-) diff --git a/src/geo2d.cpp b/src/geo2d.cpp index c119f37..ebfafa7 100644 --- a/src/geo2d.cpp +++ b/src/geo2d.cpp @@ -18,8 +18,8 @@ */ -#include"geo2d.h" -#include +#include "geo2d.h" +#include vec2::vec2(){} vec2::vec2(float _x, float _y) @@ -80,56 +80,65 @@ vec2 vec2::unit() const vec2 vec2::rotate(float a) const { vec2 r; - const float c=cos(a), - s=sin(a); + const float + c = cos(a), + s = sin(a); - r.x=c*x - s*y; - r.y=s*x + c*y; + r.x = c * x - s * y; + r.y = s * x + c * y; return r; } -float vec2::angle() const +float vec2::angle () const { - return atan(y/x); + return atan (y / x); } vec2 operator* (const float& f, const vec2& v) { - return (v*f); + return (v * f); } float distance2(const vec2& v1, const vec2& v2) { - return (v2-v1).length2(); + return (v2 - v1).length2(); } float distance(const vec2& v1, const vec2& v2) { - return (v2-v1).length(); + return (v2 - v1).length(); } float dot (const vec2& v1, const vec2& v2) { - return v1.x*v2.x+v1.y*v2.y; + return v1.x * v2.x + v1.y * v2.y; } float angle (const vec2&v1,const vec2&v2) { float a=acosf(dot(v1.unit(),v2.unit())); - while(a>M_PI) { a-=2*M_PI; } - while(a<=-M_PI) { a+=2*M_PI; } + + /* + Return an angle between -PI and PI. + Adding or subtracting 2PI always results + in the same angle. + */ + while (a > M_PI) { a -= 2*M_PI; } + while (a <= -M_PI) { a += 2*M_PI; } + return a; } -vec2 projection(const vec2& v,const vec2& on_v) +vec2 projection (const vec2& v,const vec2& on_v) { - return on_v*dot(v,on_v)/on_v.length2(); + return on_v * dot (v, on_v) / on_v.length2 (); } vec2 lineIntersection(const vec2& a1, const vec2& a2, const vec2& b1, const vec2& b2) { - float d=(a1.x-a2.x)*(b1.y-b2.y)-(a1.y-a2.y)*(b1.x-b2.x), - a=a1.x*a2.y-a1.y*a2.x, - b=b1.x*b2.y-b1.y*b2.x; - vec2 r((a*(b1.x-b2.x)-b*(a1.x-a2.x))/d,(a*(b1.y-b2.y)-b*(a1.y-a2.y))/d); + float d = (a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x), + a = a1.x * a2.y - a1.y * a2.x, + b = b1.x * b2.y - b1.y * b2.x; + + vec2 r ((a*(b1.x-b2.x)-b*(a1.x-a2.x))/d,(a*(b1.y-b2.y)-b*(a1.y-a2.y))/d); return r; } vec2 pointOnBezierCurve(float ti, const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3) { - float invti = 1.0f-ti; + float invti = 1.0f - ti; return invti*invti*invti*p0 + 3*invti*invti*ti*p1 + 3*invti*ti*ti*p2 + ti*ti*ti*p3; } diff --git a/src/geo2d.h b/src/geo2d.h index f46721e..c0f721f 100644 --- a/src/geo2d.h +++ b/src/geo2d.h @@ -18,40 +18,84 @@ */ -#ifndef GEOMETRY_H -#define GEOMETRY_H +#ifndef GEO2D_H +#define GEO2D_H + +/* + The vec2 is a vector of length 2, used for 2D space calculations. + */ struct vec2 { - float x,y; - - vec2 operator* (const float& f) const; - vec2 operator/ (const float& f) const; - vec2 operator+ (const vec2& v2) const; - vec2 operator- (const vec2& v2) const; - void operator+= (const vec2& v2); - void operator-= (const vec2& v2); - bool operator== (const vec2& other) const; + // coordinates: + float x, y; + + /* + vec2 objects can be added on, subtracted and + multiplied/divided by a scalar. + */ + + vec2 operator* (const float &f) const; + vec2 operator/ (const float &f) const; + vec2 operator+ (const vec2 &v2) const; + vec2 operator- (const vec2 &v2) const; + void operator+= (const vec2 &v2); + void operator-= (const vec2 &v2); + bool operator== (const vec2 &other) const; vec2 operator- () const; - // Length2 is computationally less expensive than Length - float length2() const; - float length() const; + /* + length2 is the squared length, it's + computationally less expensive than Length + */ + float length2 () const; + float length () const; - float angle() const; // with x-axis - vec2 unit() const; - vec2 rotate(float angle) const; + float angle () const; // with x-axis - vec2(); - vec2(float x, float y); + vec2 unit () const; // the unit vector has length 1.0 + + /** + * Rotates this vector in counter clockwise direction. + * :param angle: angle in radians + */ + vec2 rotate (float angle) const; + + vec2 (); + vec2 (float x, float y); }; -vec2 operator* (const float& f, const vec2& v); -float distance2(const vec2& v1, const vec2& v2); -float distance(const vec2& v1, const vec2& v2); -float dot (const vec2& v1, const vec2& v2); -float angle(const vec2&v1,const vec2&v2); +vec2 operator* (const float &f, const vec2 &v); + +/* + distance2 is squared distance, it's + computationally less expensive than distance. + */ +float distance2(const vec2 &v1, const vec2 &v2); +float distance(const vec2 &v1, const vec2 &v2); + +float dot (const vec2 &v1, const vec2 &v2); + +// angle between two vectors, in radians: +float angle (const vec2 &v1, const vec2 &v2); + +// projects on vector on the other: vec2 projection(const vec2& v,const vec2& on_v); -vec2 lineIntersection(const vec2& a1, const vec2& a2, const vec2& b1, const vec2& b2); -vec2 pointOnBezierCurve(float t, const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3); + +/** + * Gets the intersection between line a (from a1 to a2) + * and line b (from b1 to b2). + */ +vec2 lineIntersection (const vec2& a1, const vec2& a2, const vec2& b1, const vec2& b2); + +/** + * Calculates the position for a point on a bezier curve. + * + * :param t: should be between 0.0 and 1.0 + * :param p0, p1, p2, p3: control points that define the curve + * + * For more information, see: + * https://en.wikipedia.org/wiki/B%C3%A9zier_curve + */ +vec2 pointOnBezierCurve (float t, const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3); #endif diff --git a/src/ip.h b/src/ip.h index 525f493..dbaeda4 100644 --- a/src/ip.h +++ b/src/ip.h @@ -35,21 +35,21 @@ inline void ip2String (const IPaddress& address, char* out) { Uint8 *bytes = (Uint8 *)&address.host; sprintf (out, "%u.%u.%u.%u:%u", - (unsigned int)bytes[0], - (unsigned int)bytes[1], - (unsigned int)bytes[2], - (unsigned int)bytes[3], - (unsigned int)address.port); + (unsigned int)bytes [0], + (unsigned int)bytes [1], + (unsigned int)bytes [2], + (unsigned int)bytes [3], + (unsigned int)address.port); } inline void string2IP (const char* str, IPaddress& out) { Uint8 *bytes = (Uint8 *)&out.host; sscanf (str, "%u.%u.%u.%u:%u", - (unsigned int*)&bytes[0], - (unsigned int*)&bytes[1], - (unsigned int*)&bytes[2], - (unsigned int*)&bytes[3], - (unsigned int*)&out.port); + (unsigned int *)&bytes [0], + (unsigned int *)&bytes [1], + (unsigned int *)&bytes [2], + (unsigned int *)&bytes [3], + (unsigned int *)&out.port); } #endif diff --git a/src/server/server.cpp b/src/server/server.cpp index 168e223..73a0b5a 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -57,35 +57,40 @@ bool Server::Init() settingsPath = std::string(SDL_GetBasePath()) + SETTINGS_FILE; accountsPath = std::string(SDL_GetBasePath()) + ACCOUNT_DIR; - // load the settings from the config + // load the maxUsers setting from the config maxUsers = LoadSetting(settingsPath.c_str(), MAXLOGIN_SETTING); - if(maxUsers>0) + if (maxUsers > 0) { - users=new UserP[maxUsers]; - for(Uint64 i=0; iaccountName [0] = NULL; users[i]->ticksSinceLastContact = 0; - // Generate a RSA key to encrypt passwords in + // Generate a RSA key to encrypt login password in BIGNUM *bn = BN_new (); BN_set_word (bn, 65537); users[i]->key = RSA_new (); - bool keySuccess = RSA_generate_key_ex (users[i]->key, 1024,bn,NULL) + bool keySuccess = RSA_generate_key_ex (users[i]->key, 1024, bn, NULL) && RSA_check_key (users[i]->key); + BN_free (bn); - if(!keySuccess) + if (!keySuccess) { - RSA_free(users[i]->key); + RSA_free (users[i]->key); delete users[i]; users[i]=NULL; return NULL; } - return users[i]; + return users [i]; } } @@ -176,20 +183,20 @@ Server::UserP Server::GetUser (const IPaddress& address) for(Uint64 i = 0; i < maxUsers; i++) { if (users[i] - && users[i]->address.host == address.host - && users[i]->address.port == address.port ) + && users[i]->address.host == address.host + && users[i]->address.port == address.port) { - return users[i]; + return users [i]; } } return NULL; } Server::UserP Server::GetUser (const char* accountName) { - for(Uint64 i=0; iaccountName,accountName)==0 ) + && strcmp (users[i]->accountName, accountName)==0 ) { return users[i]; } @@ -207,10 +214,10 @@ bool Server::LoggedIn(Server::User* user) void Server::OnPlayerRemove (Server::User* user) { // Tell other players about this one's removal: - int len = USERNAME_MAXLENGTH+1; - Uint8*data=new Uint8[USERNAME_MAXLENGTH+1]; - data[0]=NETSIG_DELPLAYER; - memcpy(data+1,user->accountName,USERNAME_MAXLENGTH); + int len = USERNAME_MAXLENGTH + 1; + Uint8*data = new Uint8 [USERNAME_MAXLENGTH + 1]; + data [0] = NETSIG_DELPLAYER; + memcpy (data + 1,user->accountName, USERNAME_MAXLENGTH); // Send the message to all clients: for(Uint64 i=0; iusername, params->password)) { + // username and password match + + // register username with ip-address: strcpy (user->accountName, params->username); + user->params.hue = rand() % 360; // give the user a random color user->state.pos.x=-1000; user->state.pos.y=-1000; @@ -518,7 +532,7 @@ void Server::OnAuthenticate(const IPaddress& clientAddress, LoginParams* params) data [0] = NETSIG_LOGINSUCCESS; memcpy(data + 1, &user->params, sizeof(UserParams)); memcpy(data + 1 + sizeof(UserParams), &user->state, sizeof(UserState)); - SendToClient(clientAddress,data,len); + SendToClient (clientAddress,data,len); delete data; // Tell other users about this new user: @@ -528,8 +542,8 @@ void Server::OnAuthenticate(const IPaddress& clientAddress, LoginParams* params) { if(users[i]!=user) { - TellUserAboutUser (user,users[i]); - TellUserAboutUser (users[i],user); + TellUserAboutUser (user, users[i]); + TellUserAboutUser (users[i], user); } } } @@ -540,11 +554,11 @@ void Server::OnAuthenticate(const IPaddress& clientAddress, LoginParams* params) SendToClient (clientAddress, &response, 1); // Remove the user that requested the login: - DelUser(pendingUser); + DelUser (pendingUser); } } } -void Server::OnLoginRequest(const IPaddress& clientAddress) +void Server::OnLoginRequest (const IPaddress& clientAddress) { if (GetUser (clientAddress)) { @@ -555,22 +569,25 @@ void Server::OnLoginRequest(const IPaddress& clientAddress) } else { - UserP user = AddUser(); + UserP user = AddUser (); if (user) { + // Send the user a public key to encrypt password: + int keySize = i2d_RSAPublicKey(user->key, NULL); Uint8* data = new Uint8 [keySize + 1]; data [0] = NETSIG_RSAPUBLICKEY; - unsigned char *pe = (unsigned char*)(data + 1); + unsigned char *pe = (unsigned char *)(data + 1); i2d_RSAPublicKey (user->key, &pe); - user->address = clientAddress; - SendToClient (clientAddress, data, keySize + 1); delete [] data; + + // Register IP address: + user->address = clientAddress; } - else // we couldn't create another user + else // too many users already { Uint8 response = NETSIG_SERVERFULL; SendToClient (clientAddress, &response, 1); @@ -635,16 +652,18 @@ int Server::LoopThreadFunc (void* p) while (!server->done) // is the server still running? { - while(SDLNet_UDP_Recv (server->socket, server->in)) + // Poll for incoming packets: + while (SDLNet_UDP_Recv (server->socket, server->in)) { server->OnRequest (server->in->address, server->in->data, server->in->len); } + // Get time passed since last iteration: ticks = SDL_GetTicks(); server->Update (ticks - ticks0); ticks0 = ticks; - SDL_Delay (100); // <- this is to allow the other processes to run + SDL_Delay (100); // sleep to allow the other thread to run } return 0; @@ -656,6 +675,7 @@ int main(int argc, char** argv) if(!server.Init()) return 1; + // Take command line input: while (server.TakeCommands()); server.CleanUp(); diff --git a/src/server/server.h b/src/server/server.h index 1deca60..e70ecef 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -30,8 +30,16 @@ #include "../account.h" #define PACKET_MAXSIZE 512 -#define MAX_CHAT_LENGTH 100 +#define MAX_CHAT_LENGTH 100 // must fit inside packet +/* + A netsig byte is usually placed at the beginning + of the package data. It tells the server or client + what data will follow after it. + + In some cases, the netsig byte alone is enough + information already. + */ #define NETSIG_PINGSERVER 0x01 #define NETSIG_RSAENCRYPTED 0x02 #define NETSIG_PINGCLIENT 0x03 @@ -54,7 +62,7 @@ #define COMMAND_MAXLENGTH 256 #define SERVER_RSA_PADDING RSA_PKCS1_PADDING -inline int maxFLEN(RSA* rsa) { return (RSA_size(rsa) - 11); } +inline int maxFLEN (RSA* rsa) { return (RSA_size(rsa) - 11); } #define CONNECTION_TIMEOUT 10.0f // seconds @@ -65,7 +73,7 @@ struct LoginParams }; struct UserParams { - int hue; + int hue; // color }; struct UserState { @@ -74,8 +82,8 @@ struct UserState }; struct ChatEntry { - char username [USERNAME_MAXLENGTH], - message [MAX_CHAT_LENGTH]; + char username [USERNAME_MAXLENGTH], // who said it? + message [MAX_CHAT_LENGTH]; // what was said? }; class Server @@ -86,8 +94,8 @@ class Server IPaddress address; char accountName[USERNAME_MAXLENGTH]; // empty if not authenticated Uint32 ticksSinceLastContact; - bool pinging; - RSA* key; + bool pinging; + RSA* key; // For password encryption/decryption. UserState state; UserParams params; @@ -95,13 +103,13 @@ class Server typedef User* UserP; UserP* users; Uint64 maxUsers; - static bool LoggedIn(User*); + static bool LoggedIn (User*); - UserP AddUser(); - UserP GetUser(const IPaddress& address); - UserP GetUser(const char* accountName); - void DelUser(const Uint64 i); - void DelUser(UserP user); + UserP AddUser (); + UserP GetUser (const IPaddress& address); + UserP GetUser (const char* accountName); + void DelUser (const Uint64 i); + void DelUser (UserP user); std::list chat_history; @@ -112,35 +120,35 @@ class Server UDPpacket *in, *out, **udpPackets; - int port; + int port; UDPsocket socket; - bool done; + bool done; // if true, loopThread ends SDL_Thread *loopThread; - static int LoopThreadFunc(void* server); + static int LoopThreadFunc (void* server); - void Update(Uint32 ticks); + void Update (Uint32 ticks); - void PrintUsers() const; + void PrintUsers () const; void PrintChatHistory () const; void TellAboutLogout(User* to, const char* loggedOutUsername); - void OnRequest(const IPaddress& clientAddress, Uint8*data, int len); - void OnRSAEncrypted(const IPaddress& clientAddress, Uint8*data, int len); - void OnLoginRequest(const IPaddress& clientAddress); - void OnAuthenticate(const IPaddress& clientAddress, LoginParams* params); - void OnLogout(User* user); + void OnRequest (const IPaddress& clientAddress, Uint8*data, int len); + void OnRSAEncrypted (const IPaddress& clientAddress, Uint8*data, int len); + void OnLoginRequest (const IPaddress& clientAddress); + void OnAuthenticate (const IPaddress& clientAddress, LoginParams* params); + void OnLogout (User* user); - bool SendToClient(const IPaddress& clientAddress,const Uint8*data, int len); + bool SendToClient (const IPaddress& clientAddress,const Uint8*data, int len); - void OnPlayerRemove(User* user); + void OnPlayerRemove (User* user); - void TellUserAboutUser(User* to, User* about); + void TellUserAboutUser (User* to, User* about); - void OnChatMessage(const User*, const char*); - void OnStateSet(User* user,UserState* newState); - void SendUserStateToAll(User* user); + void OnChatMessage (const User*, const char*); + void OnStateSet (User* user,UserState* newState); + void SendUserStateToAll (User* user); void SendToAll (const Uint8*, const int len); diff --git a/src/shader.cpp b/src/shader.cpp index 940546d..7d20ef9 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -24,6 +24,11 @@ #include "err.h" #include "shader.h" +/** + * Compile either the source of a vertex or fragment shader. + * :param type: either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER + * :returns: OpenGL handle to shader, or 0 on error + */ GLuint CreateShader(const std::string& source, int type) { if(type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) @@ -32,25 +37,28 @@ GLuint CreateShader(const std::string& source, int type) return 0; } - GLint result = GL_FALSE; + GLint result; int logLength; GLuint shader = glCreateShader(type); + // Compile const char *src_ptr = source.c_str(); - glShaderSource(shader, 1, &src_ptr, NULL); - glCompileShader(shader); + glShaderSource (shader, 1, &src_ptr, NULL); + glCompileShader (shader); - glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + glGetShaderiv (shader, GL_COMPILE_STATUS, &result); if(result!=GL_TRUE) { + // Error occurred, get compile log: + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); char *errorString = new char[logLength]; glGetShaderInfoLog(shader, logLength, NULL, errorString); SetError ("Error compiling shader: %s", errorString); - delete[] errorString; + delete [] errorString; - glDeleteShader(shader); + glDeleteShader (shader); return 0; } @@ -63,33 +71,40 @@ GLuint CreateShaderProgram(const std::string& sourceVertex, const std::string& s int logLength; GLuint program=0, vertexShader, fragmentShader; - vertexShader = CreateShader(sourceVertex, GL_VERTEX_SHADER); - fragmentShader = CreateShader(sourceFragment, GL_FRAGMENT_SHADER); + // Compile the sources: + vertexShader = CreateShader (sourceVertex, GL_VERTEX_SHADER); + fragmentShader = CreateShader (sourceFragment, GL_FRAGMENT_SHADER); - if(vertexShader && fragmentShader) + if (vertexShader && fragmentShader) { + // Combine the compiled shaders into a program: program = glCreateProgram(); - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); + glAttachShader (program, vertexShader); + glAttachShader (program, fragmentShader); + glLinkProgram (program); - glGetProgramiv(program, GL_LINK_STATUS, &result); - if(result!=GL_TRUE) + glGetProgramiv (program, GL_LINK_STATUS, &result); + if (result != GL_TRUE) { + // Error occurred, get log: + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); - char *errorString = new char[logLength]; - glGetProgramInfoLog(program, logLength, NULL, errorString); + char *errorString = new char [logLength]; + glGetProgramInfoLog (program, logLength, NULL, errorString); SetError ("Error linking shader program: %s", errorString); - delete[] errorString; + delete [] errorString; - glDeleteProgram(program); + glDeleteShader (vertexShader); + glDeleteShader (fragmentShader); + glDeleteProgram (program); return 0; } } - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); + // Not needed anymore at this point: + glDeleteShader (vertexShader); + glDeleteShader (fragmentShader); return program; } diff --git a/src/shader.h b/src/shader.h index 13fdf7f..f65ef13 100644 --- a/src/shader.h +++ b/src/shader.h @@ -26,6 +26,12 @@ #include +/** + * Creates a shader program from source. + * :param sourceVertex: source of the vertex shader + * :param sourceFragment: source of the fragment shader + * :returns: OpenGL handle to the shader program, or 0 on error + */ GLuint CreateShaderProgram (const std::string& sourceVertex, const std::string& sourceFragment); #endif // SHADER_H diff --git a/src/test3d/collision.cpp b/src/test3d/collision.cpp index e48cabc..b3b8037 100644 --- a/src/test3d/collision.cpp +++ b/src/test3d/collision.cpp @@ -23,25 +23,42 @@ #include #include "../util.h" +/** + * Returns the absolute value: negative becomes positive, + * positive stays positive. + */ template -Number abs(Number n) +Number abs (Number n) { if (n < 0) return -n; else return n; } -int LineSphereIntersections(const vec3& p1, const vec3& p12, const vec3& center, float radius, double *t1, double *t2) +/** + * Calculates the intersection points between + * a sphere (center, radius) and a line (p1, p12) + * + * t1 and t2 will be set so that: + * intersection1 = p1 + t1 * p12 + * intersection2 = p1 + t2 * p12 + * + * :returns: the number of intersection points (0, 1 or 2) + */ +int LineSphereIntersections (const vec3& p1, const vec3& p12, + const vec3& center, float radius, + + double *t1, double *t2) { - double a = Dot(p12, p12); // a is always positive - double b = 2.0 * Dot(p12, p1 - center); - double c = Dot(center,center) + Dot(p1,p1) - 2.0 * Dot(center, p1) - radius * radius; - double diskriminant = b * b - 4.0 * a * c; + double a = Dot (p12, p12), // a is always positive + b = 2.0 * Dot(p12, p1 - center), + c = Dot (center, center) + Dot (p1, p1) - 2.0 * Dot (center, p1) - radius * radius, + diskriminant = b * b - 4.0 * a * c; if (diskriminant < 0 || a == 0) { - *t1=0; - *t2=0; + *t1 = 0; + *t2 = 0; return 0; } if (diskriminant == 0) @@ -49,31 +66,48 @@ int LineSphereIntersections(const vec3& p1, const vec3& p12, const vec3& center, *t2 = *t1 = (-b / (2.0 * a)); return 1; } - double sqrt_diskriminant = sqrt(diskriminant); + double sqrt_diskriminant = sqrt (diskriminant); *t1 = ((-b + sqrt_diskriminant) / (2.0 * a)); *t2 = ((-b - sqrt_diskriminant) / (2.0 * a)); + // because a is always positive, t1 > t2 return 2; } +/** + * Calculates intersection point between a line (p1, p12) and a plane + * (there's always one, unless the line is parallel to the plane) + * + * The return value is set so that: + * intersection = p1 + return_value * p12 + */ float LinePlaneIntersectionDirParameter(const vec3& p1, const vec3& p12, const Plane &plane) { vec3 p12_norm = p12.Unit(); - float distance_plane_p1 = DistanceFromPlane(p1, plane); - float divisor = Dot(plane.n, p12_norm); + + float distance_plane_p1 = DistanceFromPlane (p1, plane); + float divisor = Dot (plane.n, p12_norm); + if (divisor == 0.0f) - return 0.0f; // line lies on plane + return 0.0f; // line is parallel to plane + float t = -distance_plane_p1 / divisor; return t / p12.Length(); // at p1 t=0, at p2 t=1.0f } -vec3 LinePlaneIntersectionDir(const vec3& p1,const vec3& p12, const Plane &plane) +/** + * Calculates intersection point between a line (p1, p12) and a plane + * (there's always one, unless the line is parallel to the plane) + * + * :returns: intersection point + */ +vec3 LinePlaneIntersectionDir (const vec3& p1, const vec3& p12, const Plane &plane) { vec3 p12_norm = p12.Unit(); - float distance_plane_p1 = DistanceFromPlane(p1, plane); - float divisor = Dot(plane.n, p12_norm); + float distance_plane_p1 = DistanceFromPlane (p1, plane); + float divisor = Dot (plane.n, p12_norm); if(divisor == 0.0f) - return p1; // line lies on plane + return p1; // line parallel to plane float t = -distance_plane_p1 / divisor; @@ -81,7 +115,9 @@ vec3 LinePlaneIntersectionDir(const vec3& p1,const vec3& p12, const Plane &plane return result; } + SphereCollider :: SphereCollider (const vec3 &c, const float r) : relativeCenter(c), radius(r) {} + bool SphereCollider :: HitsTriangle (const Triangle &tri, const vec3 &startP, const vec3 &movement, vec3 &outClosestPointOnSphere, vec3 &outContactPointSphereToTriangle, vec3 &outContactNormal) { @@ -105,7 +141,7 @@ bool SphereCollider :: HitsTriangle (const Triangle &tri, const vec3 &startP, co else // at p1, the sphere is still far enough from the plane { - if (Dot(movement, (center - closestPointOnSphere)) > -0.000001f * radius) + if (Dot (movement, (center - closestPointOnSphere)) > -0.000001f * radius) // Movement is away from plane return false; @@ -128,26 +164,30 @@ bool SphereCollider :: HitsTriangle (const Triangle &tri, const vec3 &startP, co { // See if the sphere hits the edge during movement - vec3 tri_c12 = ClosestPointOnLine(tri.p[0], tri.p[1], contactPointSphereToPlane), - tri_c23 = ClosestPointOnLine(tri.p[1], tri.p[2], contactPointSphereToPlane), - tri_c13 = ClosestPointOnLine(tri.p[0], tri.p[2], contactPointSphereToPlane); - float dist_c12 = (tri_c12 - contactPointSphereToPlane).Length2(), + vec3 tri_c12 = ClosestPointOnLine (tri.p[0], tri.p[1], contactPointSphereToPlane), + tri_c23 = ClosestPointOnLine (tri.p[1], tri.p[2], contactPointSphereToPlane), + tri_c13 = ClosestPointOnLine (tri.p[0], tri.p[2], contactPointSphereToPlane); + float dist_c12 = (tri_c12 - contactPointSphereToPlane).Length2(), dist_c23 = (tri_c23 - contactPointSphereToPlane).Length2(), dist_c13 = (tri_c13 - contactPointSphereToPlane).Length2(); - if(dist_c12 < dist_c13) + if (dist_c12 < dist_c13) { - if(dist_c12 < dist_c23) contactPointSphereToTriangle = tri_c12; - else contactPointSphereToTriangle = tri_c23; + if (dist_c12 < dist_c23) + contactPointSphereToTriangle = tri_c12; + else + contactPointSphereToTriangle = tri_c23; } else { - if(dist_c13 < dist_c23) contactPointSphereToTriangle = tri_c13; - else contactPointSphereToTriangle = tri_c23; + if(dist_c13 < dist_c23) + contactPointSphereToTriangle = tri_c13; + else + contactPointSphereToTriangle = tri_c23; } double t1, t2; - if(LineSphereIntersections(contactPointSphereToTriangle, movement, center, radius, &t1, &t2)) + if (LineSphereIntersections (contactPointSphereToTriangle, movement, center, radius, &t1, &t2)) { if(t1 <= 0 && t2 < 0) { @@ -182,10 +222,10 @@ bool FeetCollider :: HitsTriangle (const Triangle &tri, const vec3 &p, const vec { const Plane plane = tri.GetPlane(); - if (abs (Dot(plane.n, -toFeet)) < 0.0001f) + if (abs (Dot (plane.n, -toFeet)) < 0.0001f) return false; // plane is parallel to feet direction - vec3 pOnGroundUnderP = LinePlaneIntersectionDir(p, toFeet, plane), + vec3 pOnGroundUnderP = LinePlaneIntersectionDir (p, toFeet, plane), feet_start = p + toFeet, contactPointFeetToPlane; @@ -210,7 +250,7 @@ bool FeetCollider :: HitsTriangle (const Triangle &tri, const vec3 &p, const vec contactPointFeetToPlane = feet_start + t * movement; } - if (!PointInsideTriangle(tri, contactPointFeetToPlane)) + if (!PointInsideTriangle (tri, contactPointFeetToPlane)) { return false; } @@ -219,6 +259,7 @@ bool FeetCollider :: HitsTriangle (const Triangle &tri, const vec3 &p, const vec closestPointOnFeet = feet_start; outContactPoint = contactPointFeetToPlane; outContactNormal = plane.n; + return true; } #define COLLISION_MAXITERATION 10 @@ -251,6 +292,7 @@ vec3 CollisionMove (const vec3& p1, const vec3& p2, bool pushingSomething = false; + // Iterate over every triangle and every collider to detect hits: for(int i = 0; i < n_triangles; i++) { for (int c = 0; c < n_colliders; c++) @@ -260,9 +302,13 @@ vec3 CollisionMove (const vec3& p1, const vec3& p2, if (pCollider->HitsTriangle (triangles [i], current_p, targetMovement, testClosestPointOnObject, testContactPoint, testNormal)) { + // Collider hit a triangle + dist2 = (testContactPoint - testClosestPointOnObject).Length2(); if (dist2 < smallestDist) { + // The closest hit on the path gets priority + smallestDist = dist2; contactPoint = testContactPoint; @@ -296,14 +342,21 @@ vec3 CollisionMove (const vec3& p1, const vec3& p2, targetMovement = pushingMovement; j++; + + /* + We moved up to the wall and adjusted our movement, + but we might encounter a new wall while moving along this one. + Do another iteration to find out.. + */ } - else + else // unhindered movement { current_p += targetMovement; return current_p; } } + // Don't go on iterating forever in corners! while ((targetMovement.Length2() > 1.0e-8f) && j < COLLISION_MAXITERATION); return current_p; @@ -344,6 +397,8 @@ bool TestOnGround (const vec3& p, if (pCollider->HitsTriangle (triangles [i], p, -up, testClosestPointOnObject, testContactPoint, testNormal)) { + // Collider hits floor when moved down, now see if the floor's close enough: + fakePlane.n = testNormal; fakePlane.d = -Dot (fakePlane.n, testContactPoint); @@ -399,8 +454,11 @@ vec3 PutOnGround (const vec3& p, if (pCollider->HitsTriangle (triangles [i], p, -smallest * up, testClosestPointOnObject, testContactPoint, testNormal)) { + // Collider hits floor when moved down, now see if the floor's close enough: + movement = testContactPoint - testClosestPointOnObject; dist2 = movement.Length2(); + if (dist2 < smallest) { smallest = dist2; @@ -452,9 +510,13 @@ vec3 CollisionWalk (const vec3& p1, const vec3& p2, if (pCollider->HitsTriangle (triangles [i], current_p, targetMovement, testClosestPointOnObject, testContactPoint, testNormal)) { + // The collider hit the triangle on the way. + dist2 = (testContactPoint - testClosestPointOnObject).Length2(); if (dist2 < smallestDist) { + // The closest hit gets priority: + smallestDist = dist2; contactPoint = testContactPoint; @@ -508,13 +570,24 @@ vec3 CollisionWalk (const vec3& p1, const vec3& p2, targetMovement = pushingMovement; j++; + + /* + We moved up to the wall and adjusted our movement, + but we might encounter a new wall while moving along this one. + Do another iteration to find out.. + */ } - else + else // unhindered movement { current_p += targetMovement; // Put it back on the ground, if any ground_p = PutOnGround (current_p, colliders, n_colliders, triangles, n_triangles, min_cosine, up); + + /* + Distance to unground position must not be too large. + Take target movement as benchmark. + */ if ((ground_p - current_p).Length2() < targetMovement.Length2()) { return ground_p; @@ -523,6 +596,7 @@ vec3 CollisionWalk (const vec3& p1, const vec3& p2, return current_p; } } + // Don't go on iterating forever in corners! while ((targetMovement.Length2() > 1.0e-8f) && j < COLLISION_MAXITERATION); return current_p; @@ -534,301 +608,20 @@ vec3 CollisionTraceBeam(const vec3 &p1, const vec3 &p2, const Triangle *triangle return p1; // otherwise we might get unexpected results vec3 p12 = p2 - p1, isect = p2, newisect; + + // For every triangle, see if the beam goes through: for(int i = 0; i < n_triangles; i++) { - newisect = LinePlaneIntersectionDir(p1, p12, triangles[i].GetPlane()); + newisect = LinePlaneIntersectionDir (p1, p12, triangles[i].GetPlane()); - if (!PointInsideTriangle(triangles[i], newisect)) + if (!PointInsideTriangle (triangles[i], newisect)) continue; vec3 delta = newisect - p1; - if( delta.Length2() < (p1 - isect).Length2() && Dot(delta, p12) > 0) + if (delta.Length2() < (p1 - isect).Length2() && Dot (delta, p12) > 0) isect = newisect; } return isect; } -/* float GetGroundSlope (const vec3 &p1, const vec3 &p2, const Triangle *triangles, const int n_triangles) -{ - if(p1 == p2) - return 0; - - float smallest = 1.0e+15f, dist2, slope; - Plane plane; - vec3 isect1, isect2, p12; - for(int i = 0; i < n_triangles; i++) - { - plane = triangles[i].GetPlane(); - - if (abs(Dot (plane.n, VEC_UP)) < 1.0e-8f) - - // skip parallels - continue; - - isect1 = LinePlaneIntersectionDir(p1, VEC_DOWN, plane); - - dist2 = (isect1 - p1).Length2(); - if (dist2 < smallest) - { - smallest = dist2; - isect2 = LinePlaneIntersectionDir(p2, VEC_DOWN, plane); - - p12 = isect2 - isect1; - slope = p12.y / sqrt(sqr (p12.x) + sqr (p12.z)); - } - } - - return slope; -} -vec3 CollisionMoveFeet (const vec3& p1, const vec3& p2, const float height, const Triangle *triangles, const int n_triangles) -{ - vec3 feet_start = {p1.x, p1.y - height, p1.z}, - - pOnGroundUnderP1, - pContactPlane, - - desiredMovement = p2 - p1, - allowedMovement = desiredMovement; - - const vec3 requested_mv = desiredMovement; - - Plane closestPlane; - - int j = 0; - do - { - float smallestDist = 1.0e+15f, - start_above, - head_start_above, - dist2; - bool pushing = false; - - for(int i = 0; i < n_triangles; i++) - { - const Triangle *tri = &triangles[i]; - const Plane plane = tri->GetPlane(); - - if (abs (Dot(plane.n, VEC_UP)) < 0.0001f) - continue; // parallel to fall direction - - pOnGroundUnderP1 = LinePlaneIntersectionDir(p1, VEC_DOWN, plane); - - start_above = (feet_start - pOnGroundUnderP1).y; - head_start_above = start_above + height; - - if (start_above < 0 && head_start_above > 0) // feet sticking through ground - { - pContactPlane = {feet_start.x, feet_start.y - start_above, feet_start.z}; - } - else - { - vec3 projection = PlaneProjection(feet_start, plane); - - if (Dot ((projection - feet_start), desiredMovement) < 0.0001f) - continue; // not moving towards floor - - float t = LinePlaneIntersectionDirParameter(feet_start, desiredMovement, plane); - if((t > 1.0f) || (t < 0)) - continue; // no contact on the way to p2 - else - pContactPlane = feet_start + t * desiredMovement; - } - - if (!PointInsideTriangle(*tri, pContactPlane)) - continue; - - dist2 = (pContactPlane - feet_start).Length2(); - if (dist2 < smallestDist) - { - smallestDist = dist2; - allowedMovement = pContactPlane - feet_start; - closestPlane = plane; - } - pushing = true; - } - - if (pushing) - { - //plane projection of the movement: - vec3 delta = LinePlaneIntersectionDir(feet_start, desiredMovement, closestPlane) - feet_start; - - if(Dot(requested_mv, delta) < 0) - { - delta = {0, 0, 0}; - } - - feet_start += allowedMovement + closestPlane.n * 1.0e-3f; - desiredMovement = delta; - allowedMovement = desiredMovement; - - j++; - } - else - { - feet_start += allowedMovement; - return {feet_start.x, feet_start.y + height, feet_start.z}; - } - } - while ((desiredMovement.Length2() > 1.0e-8f) && j < COLLISION_MAXITERATION); - - return {feet_start.x, feet_start.y + height, feet_start.z}; -} -vec3 CollisionMoveSphere (const vec3& _p1, const vec3& _p2, float radius, const Triangle *triangles, const int n_triangles) -{ - if(_p1==_p2) - return _p1; - - vec3 p1 = _p1, - p2 = _p2, - p12 = p2 - p1; - - const vec3 ori_p12 = p12; - unsigned int j = 0; - float radius2 = radius * radius; - - vec3 newmove = p12, - newClosestPointOnSphere, - newContactPointSphereToTriangle; - - do - { - float distanceCenterToTriangle=1.0e+15f; - bool pushing=false; - for(int i = 0; i < n_triangles; i++) - { - const Triangle *tri = &triangles[i]; - const Plane plane = tri->GetPlane(); - - vec3 normal = plane.n, - p_move, - center = p1, - ClosestPointOnSphere; - - float distanceCenterToPlane = DistanceFromPlane(center, plane); - - if (distanceCenterToPlane > 0) - ClosestPointOnSphere = center - radius * normal; - else - ClosestPointOnSphere = center + radius * normal; - - vec3 contactPointSphereToPlane; - if (fabs (distanceCenterToPlane) < radius * 0.9999f) - - // sphere lies too close to plane - contactPointSphereToPlane = center - distanceCenterToPlane * normal; - - else // at p1, the sphere is still far enough from the plane - { - if (Dot(p12, (center - ClosestPointOnSphere)) > -0.000001f * radius) - // Movement is away from plane - continue; - - float t = LinePlaneIntersectionDirParameter (ClosestPointOnSphere, p12, plane); - if ((t > 1.0f) || (t < -radius/p12.Length())) - - // Movement doesn't reach plane - continue; - else - contactPointSphereToPlane = ClosestPointOnSphere + t * p12; - } - - vec3 contactPointSphereToTriangle; - if (PointInsideTriangle (*tri, contactPointSphereToPlane)) - { - // Then it's easy - contactPointSphereToTriangle = contactPointSphereToPlane; - } - else // hit point is outside triangle - { - // See if the sphere hits the edge during movement - - vec3 tri_c12 = ClosestPointOnLine(tri->p[0], tri->p[1], contactPointSphereToPlane), - tri_c23 = ClosestPointOnLine(tri->p[1], tri->p[2], contactPointSphereToPlane), - tri_c13 = ClosestPointOnLine(tri->p[0], tri->p[2], contactPointSphereToPlane); - float dist_c12 = (tri_c12 - contactPointSphereToPlane).Length2(), - dist_c23 = (tri_c23 - contactPointSphereToPlane).Length2(), - dist_c13 = (tri_c13 - contactPointSphereToPlane).Length2(); - - if(dist_c12 < dist_c13) - { - if(dist_c12 < dist_c23) contactPointSphereToTriangle = tri_c12; - else contactPointSphereToTriangle = tri_c23; - } - else - { - if(dist_c13 < dist_c23) contactPointSphereToTriangle = tri_c13; - else contactPointSphereToTriangle = tri_c23; - } - - double t1, t2; - if(LineSphereIntersections(contactPointSphereToTriangle, p12, center, radius, &t1, &t2)) - { - if (t1 <= 0 && t2 < 0) - { - if (t1 < -1.0f) - continue; // Too far away. - - ClosestPointOnSphere = t1 * p12 + contactPointSphereToTriangle; - } - else if(t1 > 0 && t2 < 0) - { - if (abs(t1) < abs(t2)) ClosestPointOnSphere = t1 * p12 + contactPointSphereToTriangle; - else ClosestPointOnSphere = t2 * p12 + contactPointSphereToTriangle; - } - else // if(t1>0 && t2>0) - continue; // Too far away. - } - else - continue; // No intersections with this sphere. - } - p_move = contactPointSphereToTriangle - ClosestPointOnSphere; - - // Pick the shortest possible moving distance of all triangles - float dist2 = (contactPointSphereToTriangle - center).Length2(); - if(dist2 < distanceCenterToTriangle) - { - distanceCenterToTriangle = dist2; - newmove = p_move; - newClosestPointOnSphere = ClosestPointOnSphere; - newContactPointSphereToTriangle = contactPointSphereToTriangle; - } - pushing = true; - } - - if (pushing) // movement needs to be adjusted - { - // Calculate a fictional plane - Plane plane; - plane.n = (p1 - newClosestPointOnSphere).Unit(); - plane.d = -Dot(plane.n, newContactPointSphereToTriangle); - - // plane projection of the movement: - vec3 delta = LinePlaneIntersectionDir( newClosestPointOnSphere + p12, plane.n, plane)- newContactPointSphereToTriangle; - - if (Dot(ori_p12, delta) < 0) // moves in opposite direction, let's not! - { - delta = {0, 0, 0}; - } - - // Do the moving part that collision allows - p1 += newmove + 0.0001f * radius * plane.n; - - // Reset our goal to what last plane's projection allows - p2 = p1 + delta; - p12 = p2 - p1; - newmove = p12; - - // count the number of pushes - j++; - } - else - { - p1 += newmove; - return p1; - } - } - while((p12.Length2() > 1.0e-8f * radius2) && j < COLLISION_MAXITERATION); - - return p1; -} */ diff --git a/src/test3d/hub.cpp b/src/test3d/hub.cpp index 7666971..a118fd7 100644 --- a/src/test3d/hub.cpp +++ b/src/test3d/hub.cpp @@ -24,6 +24,7 @@ #include "../xml.h" #include "../err.h" +// Color for the help text in each of the scenes (RGB): const GLfloat textColors [][3] = {{1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; HubScene::HubScene (App *pApp) : Scene (pApp), @@ -56,6 +57,7 @@ HubScene::HubScene (App *pApp) : Scene (pApp), pToonScene = new ToonScene (pApp); + // Start with this scene: pCurrent = pShadowScene; help = 0; } @@ -83,8 +85,9 @@ bool HubScene::Init () if (!fontInput) // file or archive missing return false; - xmlDocPtr pDoc = ParseXML(fontInput); - fontInput->close(fontInput); + // Parse the svg as xml document: + xmlDocPtr pDoc = ParseXML (fontInput); + fontInput->close (fontInput); if (!pDoc) { @@ -92,6 +95,7 @@ bool HubScene::Init () return false; } + // Convert xml to font object: success = ParseSVGFont (pDoc, 16, &font); xmlFreeDoc (pDoc); @@ -105,10 +109,16 @@ bool HubScene::Init () } void HubScene::Update (float dt) { + // Update current scene: pCurrent -> Update (dt); - const Uint8 *state = SDL_GetKeyboardState(NULL); - if (state[SDL_SCANCODE_H]) + /* + Update help text alpha. + If the key is down alpha must be 1.0, + else decrease gradually. + */ + const Uint8 *state = SDL_GetKeyboardState (NULL); + if (state [SDL_SCANCODE_H]) { alphaH = 1.0f; } @@ -120,8 +130,9 @@ void HubScene::Render () int w, h; SDL_GL_GetDrawableSize (pApp->GetMainWindow (), &w, &h); - glViewport(0, 0, w, h); + glViewport (0, 0, w, h); + // Render current scene: pCurrent -> Render (); // Render the text: @@ -132,7 +143,10 @@ void HubScene::Render () glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + /* + Screen is a w x h rectangle. + Positive y means down. + */ glMatrixMode(GL_PROJECTION); matrix4 matScreen = matOrtho(0.0f, w, 0.0f, h, -1.0f, 1.0f); glLoadMatrixf (matScreen.m); @@ -141,6 +155,11 @@ void HubScene::Render () glLoadIdentity(); glMultMatrixf (matTranslation(10.0f, 10.0f, 0.0f).m); + /* + When the help key is down (alpha = 1.0), help is shown. + When alpha goes down to 0.0, "Press 'h' for help shows up" + */ + GLfloat maxWidth = w - 20.0f; glColor4f (textColors [help][0], textColors [help][1], textColors [help][2], 1.0f - alphaH); glRenderText (&font, "Press 'h' for help", TEXTALIGN_LEFT, maxWidth); @@ -152,6 +171,7 @@ void HubScene::OnEvent(const SDL_Event *event) { Scene :: OnEvent (event); + // pass on event to current scene: pCurrent -> OnEvent (event); } void HubScene::OnKeyPress (const SDL_KeyboardEvent *event) @@ -161,6 +181,8 @@ void HubScene::OnKeyPress (const SDL_KeyboardEvent *event) if(event->keysym.sym == SDLK_ESCAPE) pApp->ShutDown(); + // These keys switch between scenes: + if(event->keysym.sym == SDLK_F1) { pCurrent = pShadowScene; diff --git a/src/test3d/hub.h b/src/test3d/hub.h index 1a91b91..ecf3fff 100644 --- a/src/test3d/hub.h +++ b/src/test3d/hub.h @@ -27,19 +27,30 @@ #include "../font.h" +/* + The hub scene manager switching between scenes. + It's also responsible for showing help text. + */ class HubScene : public App::Scene{ private: WaterScene *pWaterScene; ShadowScene *pShadowScene; ToonScene *pToonScene; + + // Currently rendered scene: Scene *pCurrent; + // Font for the help text shown: Font font; + // text alpha value GLfloat alphaH; + // current help string index: int help; + + // help strings: std::string helpText [3]; public: void OnEvent (const SDL_Event *event); diff --git a/src/test3d/toon.cpp b/src/test3d/toon.cpp index ee2b838..7367bdb 100644 --- a/src/test3d/toon.cpp +++ b/src/test3d/toon.cpp @@ -127,6 +127,7 @@ void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, /* Almost the same as a normal mesh rendering, except that the vertices are moved along their normals. + This makes the rendered mesh a bit larger than the original. */ if(pMeshData->subsets.find(id) == pMeshData->subsets.end()) @@ -140,10 +141,10 @@ void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, const vec3 *n; vec3 p; + // Give OpenGL all quads: + glBegin(GL_QUADS); for (std::list ::const_iterator it = pSubset->quads.begin(); it != pSubset->quads.end(); it++) { - glBegin(GL_QUADS); - PMeshQuad pQuad = *it; for (size_t j = 0; j < 4; j++) { @@ -155,10 +156,10 @@ void RenderUnAnimatedSubsetExtension (const MeshData *pMeshData, std::string id, glNormal3f (n->x, n->y, n->z); glVertex3f (p.x, p.y, p.z); } - - glEnd(); } + glEnd(); + // Give OpenGL all triangles: glBegin(GL_TRIANGLES); for (std::list ::const_iterator it = pSubset->triangles.begin(); it != pSubset->triangles.end(); it++) { @@ -189,7 +190,7 @@ void ToonScene::Render () SDL_GL_GetDrawableSize (pApp->GetMainWindow (), &w, &h); - // Set the 3d projection matrix: + // Set orthographic projection matrix: glMatrixMode (GL_PROJECTION); matrix4 matScreen = matOrtho(-w / 2, w / 2, -h / 2, h / 2, -1.0f, 1.0f); glLoadMatrixf (matScreen.m); @@ -233,7 +234,7 @@ void ToonScene::Render () glClearStencil (0); glClear (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // Set the 3d projection matrix: + // Set perspective 3d projection matrix: glMatrixMode (GL_PROJECTION); matrix4 matCamera = matPerspec(VIEW_ANGLE, (GLfloat) w / (GLfloat) h, NEAR_VIEW, FAR_VIEW); glLoadMatrixf(matCamera.m); @@ -260,7 +261,7 @@ void ToonScene::Render () glCullFace (GL_FRONT); glEnable (GL_DEPTH_TEST); - glDepthMask (GL_FALSE); + glDepthMask (GL_FALSE); // no depth values, we need to draw inside it. glStencilFunc (GL_ALWAYS, 1, STENCIL_MASK); glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); @@ -282,7 +283,7 @@ void ToonScene::Render () glColor4fv (meshDataHead.subsets.at("0").diffuse); RenderUnAnimatedSubset (&meshDataHead, "0"); // head - /* The face is inside the head, but drawn over it */ + // The face is inside the head, but drawn over it glDisable (GL_DEPTH_TEST); glColor4fv (meshDataHead.subsets.at("1").diffuse); @@ -296,6 +297,7 @@ void ToonScene::Render () glEnable (GL_DEPTH_TEST); + // Hair must be drawn over the face: glColor4fv (meshDataHead.subsets.at("2").diffuse); RenderUnAnimatedSubset (&meshDataHead, "2"); // hair diff --git a/src/test3d/toon.h b/src/test3d/toon.h index 1202e3c..3b3a72a 100644 --- a/src/test3d/toon.h +++ b/src/test3d/toon.h @@ -37,14 +37,17 @@ class ToonScene : public App::Scene // camera angles GLfloat angleY, angleX, distCamera; + // Background texture: Texture texBG; + // Head mesh MeshData meshDataHead; + // Handle to toon shader GLuint shaderProgram; public: - ToonScene (App*); + ToonScene (App *); ~ToonScene (); bool Init (void); diff --git a/src/util.cpp b/src/util.cpp index 4ae9416..f0e95a8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -27,36 +27,36 @@ void GLErrorString(char *out, GLenum status) { - switch(status) + switch (status) { case GL_INVALID_ENUM: - strcpy(out, "GL_INVALID_ENUM"); + strcpy (out, "GL_INVALID_ENUM"); break; case GL_INVALID_VALUE: - strcpy(out, "GL_INVALID_VALUE"); + strcpy (out, "GL_INVALID_VALUE"); break; case GL_INVALID_OPERATION: - strcpy(out, "GL_INVALID_OPERATION"); + strcpy (out, "GL_INVALID_OPERATION"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: - strcpy(out, "GL_INVALID_FRAMEBUFFER_OPERATION"); + strcpy (out, "GL_INVALID_FRAMEBUFFER_OPERATION"); break; case GL_OUT_OF_MEMORY: - strcpy(out, "GL_OUT_OF_MEMORY"); + strcpy (out, "GL_OUT_OF_MEMORY"); break; case GL_STACK_UNDERFLOW: - strcpy(out, "GL_STACK_UNDERFLOW"); + strcpy (out, "GL_STACK_UNDERFLOW"); break; case GL_STACK_OVERFLOW: - strcpy(out, "GL_STACK_OVERFLOW"); + strcpy (out, "GL_STACK_OVERFLOW"); break; default: - sprintf(out, "unknown error 0x%.8X", status); + sprintf (out, "unknown error 0x%.8X", status); break; } } -bool ReadAll(SDL_RWops *io, std::string &out) +bool ReadAll (SDL_RWops *io, std::string &out) { const size_t bufsize = 256; size_t n; diff --git a/src/vec.h b/src/vec.h index d47f103..08fc730 100644 --- a/src/vec.h +++ b/src/vec.h @@ -34,8 +34,13 @@ #define PI 3.1415926535897932384626433832795 +/* + vec3 is a vector of length 3, used for 3D space calculations. + */ + struct vec3 { + // Coordinates: x, y, and z, or v[0], v[1] and v[2] union { struct { float x, y, z; @@ -52,7 +57,10 @@ struct vec3 z = v.z; } - // Length2 is computationally less expensive than Length + /* + Length2 is the squared length, it's + computationally less expensive than Length + */ float Length() const {return sqrt(x*x+y*y+z*z);} float Length2() const {return (x*x+y*y+z*z);} @@ -65,6 +73,11 @@ struct vec3 else return *this; } + /* + vec3 objects can be added on, subtracted and + multiplied/divided by a scalar. + */ + vec3 operator- () const { return vec3(-x,-y,-z); } vec3 operator- (const vec3 &v) const { return vec3(x-v.x,y-v.y,z-v.z); } vec3 operator+ (const vec3 &v) const { return vec3(x+v.x,y+v.y,z+v.z); } From 070bab46a0301699e77bd2fb6d6b4f964b66d6bc Mon Sep 17 00:00:00 2001 From: cbaakman Date: Tue, 18 Aug 2015 19:29:24 +0200 Subject: [PATCH 05/10] BUGFIX: account.o needs err.o --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cd64120..a01da71 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ obj/%.o: src/%.cpp mkdir -p $(@D) gcc -std=c++0x -D DEBUG -c $< -o $@ $(INCDIRS:%=-I%) -bin/server: obj/geo2d.o obj/str.o obj/ini.o obj/account.o obj/server/server.o +bin/server: obj/geo2d.o obj/str.o obj/ini.o obj/account.o obj/server/server.o obj/err.o gcc $^ -o $@ -lstdc++ $(SERVERLIBS:%=-l%) $(LIBDIRS:%=-L%) bin/client: obj/geo2d.o obj/ini.o obj/client/client.o obj/util.o obj/client/connection.o obj/str.o obj/err.o obj/client/textscroll.o\ @@ -27,5 +27,5 @@ bin/test3d: obj/test3d/water.o obj/ini.o obj/test3d/hub.o obj/xml.o obj/str.o ob obj/io.o obj/texture.o obj/test3d/mesh.o obj/util.o obj/font.o obj/test3d/collision.o obj/test3d/toon.o gcc $^ -o $@ $(TEST3DLIBS:%=-l%) $(LIBDIRS:%=-L%) -bin/manager: obj/manager/manager.o obj/str.o obj/account.o +bin/manager: obj/manager/manager.o obj/str.o obj/account.o obj/err.o gcc $^ -o $@ -lstdc++ $(MANAGERLIBS:%=-l%) $(LIBDIRS:%=-L%) From 71499915cb02e799c743c84404df18831acf0fbb Mon Sep 17 00:00:00 2001 From: cbaakman Date: Wed, 19 Aug 2015 21:16:28 +0200 Subject: [PATCH 06/10] more info when shader compilation fails --- src/shader.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/shader.cpp b/src/shader.cpp index 7d20ef9..189cfb3 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -39,7 +39,7 @@ GLuint CreateShader(const std::string& source, int type) GLint result; int logLength; - GLuint shader = glCreateShader(type); + GLuint shader = glCreateShader (type); // Compile const char *src_ptr = source.c_str(); @@ -50,12 +50,19 @@ GLuint CreateShader(const std::string& source, int type) if(result!=GL_TRUE) { // Error occurred, get compile log: + glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &logLength); - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + char *errorString = new char [logLength + 1]; + glGetShaderInfoLog (shader, logLength, NULL, errorString); + + if (type == GL_VERTEX_SHADER) + + SetError ("Error compiling vertex shader: %s", errorString); + + else if (type == GL_FRAGMENT_SHADER) + + SetError ("Error compiling fragment shader: %s", errorString); - char *errorString = new char[logLength]; - glGetShaderInfoLog(shader, logLength, NULL, errorString); - SetError ("Error compiling shader: %s", errorString); delete [] errorString; glDeleteShader (shader); @@ -79,8 +86,10 @@ GLuint CreateShaderProgram(const std::string& sourceVertex, const std::string& s { // Combine the compiled shaders into a program: program = glCreateProgram(); + glAttachShader (program, vertexShader); glAttachShader (program, fragmentShader); + glLinkProgram (program); glGetProgramiv (program, GL_LINK_STATUS, &result); From 968bc62afbbceb7abb54a036b9269655fdbce188 Mon Sep 17 00:00:00 2001 From: cbaakman Date: Wed, 19 Aug 2015 21:16:58 +0200 Subject: [PATCH 07/10] made error string bigger, it was too small --- src/err.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/err.cpp b/src/err.cpp index 3b90b85..69947d4 100644 --- a/src/err.cpp +++ b/src/err.cpp @@ -24,10 +24,11 @@ #include #include -#define ERRSTR_LEN 512 +#define ERRSTR_LEN 16384 // String to store the error in: -char error [ERRSTR_LEN] = ""; +char error [ERRSTR_LEN] = "", + tmp [ERRSTR_LEN]; const char *GetError () { @@ -35,16 +36,17 @@ const char *GetError () } void SetError (const char* format, ...) { - // use a temporary buffer, because 'error' might be one of the args - char tmp [ERRSTR_LEN]; - // Insert args: va_list args; va_start (args, format); - vsprintf (tmp, format, args); + // use the temporary buffer, because 'error' might be one of the args + int res = vsprintf (tmp, format, args); va_end (args); - // copy from temporary buffer: - strcpy (error, tmp); + if (res > 0) + { + // copy from temporary buffer: + strcpy (error, tmp); + } } From f830d41a67e393625ce2a6bda5260e420b93f9a3 Mon Sep 17 00:00:00 2001 From: cbaakman Date: Wed, 19 Aug 2015 23:26:55 +0200 Subject: [PATCH 08/10] added the GLFrameBufferErrorString function --- src/util.cpp | 33 +++++++++++++++++++++++++++++++++ src/util.h | 5 +++++ 2 files changed, 38 insertions(+) diff --git a/src/util.cpp b/src/util.cpp index f0e95a8..2b8f96a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -55,6 +55,39 @@ void GLErrorString(char *out, GLenum status) break; } } +void GLFrameBufferErrorString (char *out, GLenum status) +{ + switch (status) + { + case GL_FRAMEBUFFER_UNDEFINED: + strcpy (out, "GL_FRAMEBUFFER_UNDEFINED"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + strcpy (out, "GL_FRAMEBUFFER_UNSUPPORTED"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: + strcpy (out, "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"); + break; + default: + sprintf (out, "unknown error 0x%.8X", status); + break; + } +} bool ReadAll (SDL_RWops *io, std::string &out) { diff --git a/src/util.h b/src/util.h index 80cdec3..8f43caf 100644 --- a/src/util.h +++ b/src/util.h @@ -72,6 +72,11 @@ bool ReadAll (SDL_RWops *, std::string &out); */ void GLErrorString (char *out, GLenum status); +/** + * Converts a GL framebuffer error status to a string. + */ +void GLFrameBufferErrorString (char *out, GLenum status); + /** * Gives a h,s,v color to OpenGL */ From ff764f934278913a93392b20be29207cdd730faa Mon Sep 17 00:00:00 2001 From: cbaakman Date: Wed, 19 Aug 2015 23:39:01 +0200 Subject: [PATCH 09/10] reflection and refraction are now depth dependent The rendering function and fragment shader have been changed. The amount of displacement is now determined by the depth difference between the displaced object and the water. Thus the deeper under water, the more refraction displacement. --- bin/test3d.zip | Bin 2922868 -> 2923099 bytes src/test3d/water.cpp | 277 ++++++++++++++++++++++++++++++------------- src/test3d/water.h | 8 +- 3 files changed, 198 insertions(+), 87 deletions(-) diff --git a/bin/test3d.zip b/bin/test3d.zip index 019917a4a7f2de295003ca104760f6e2a828b0a4..6ccebb2435a11850bfe025e27c1b36e2e31a16ba 100644 GIT binary patch delta 1118 zcmeyeX%pk^Et?n{S{PfHT9{i{T3B1yTG(4SS~y#{TDV(yT6kOdTKHQ8S_E5!T7+9f zT0~pKTEtrW_t|e3%#* zuCOsM2r|ep6lWx+q!tzHmnW8_7U`uGXM~1uGB78vyAle*r4`%^j4Ush85qFC+K`iZ zw+#erz2gntPnL@4?=*2L_PiJ!z2L-J4Hh@4n=BfamcH0}Vt={EscjPao{g^-q?+X4 zo89YuGJC0XMt$UFffefW4?b9SA%a`ytU=r4)xX!?yn0_OHe`pvXY-_rq9h*f+QQ zmy7}2M|mnlpIDt+c3CDbzp;?lt14kWn89wo4IRmMf<Mub{a)fS>qas6$&)O1Zn*5rFe{#!Vts4p zg-v``0vUTe1kGN`irk%9uw6f9Wy>Xz|9?2<%Fk2yZLE8uUnJ~)Dpz^U{I~fN{yy;9 z{rT{zzY5du=gSJ+ot18VX$Sj{=LhU__c)*2^G<(35c74`pci|B_j?`J;SY>^v_HU` znMH(wfq{eJ+iqd^SA6{5)j-}&AO@z*=^Li&h;RW@W5=v3q4Q>4nO^OvrkeFg>-2e_ zz!Sb_&Ro9mWYx1rEgiR)JwNjMV2B0-;{^E$@pB?4&78kHVfBQtpeZxL=dgt=SjZW2 zfO873=h}jE=k>ih%{s1XvuPP#Fb=)obZuGq!Ug?@^usT(t=x3%LR?d5wW{9RtuYKB zhfRMlT}Pr_(Mb)6)qz+8h&6#&3y8J1D>~^ghfcpYU5CROGhayneZauL$e;iuXWOe` z%Vn(KTsHl}R2>-wOwS`5VB|D?Jz5sSQr>Ar|AIQ0|0go*8ul|n z%gn$a$iTo*oROH4T2!oGo>-Dvq?cBl(Haz(-((0PSfJJ-$Ib5CyC zo@&S|cVkIF_$o*7|G)XTgnMp!c-?+o8^8a3)o-UIUe5zQ)u;y^*EWb)Yr0HG*!Y#% zEcLW^JLgqD_@&Xs!#AV;%mM|4>Ap6Bu9-O|;!)arx3zD`XwuxEer=8S(j#m| zdR)({-)(dv^-Y2Ft0B74@fjAwkUu3T##RxDX9_u_M+ zQKQSG{fTB0tk%8kIy@;sGg7)$A7-nbGuZf1VDk#~`<9m-B9q!P)-0biyT1Elnc=o+ zO$&RExpE&?j$3?$Gg9rk{@G_UrFFG9e*LNQE?E2JkZ72DlZTGcX4Y%%K^9!g*K$Xn z{JqYsbCTELMRgUMuS=}Iu|VGAvUQmE(l5`HfAPFL`@Su7Y4qR9{@~B{7N+~pS}qHl zc~)VE=i8n8_kMEYiT{6P%~zRuS)sBAOwTpWea(ExHgleC^wQ=emIEt_6LU7#?vVbq zYr~v+h5&D777<{Ka4^gXIN^5qtVT{1kav5!r<0m2`wE}ZP#~V3>!hZd^7PSDt<&dy z0#Ep!Idl2Klc%emJ$=-2;^wmFM}8}Y6f*5({CRYy>dc>&+cH&MJ1dW7Iz;mNW_QGR zWVII8)dhNOaa z9f&o6SQCh~fLMF`cPAZ%(0X|Wh*L3>lnT(%AfN!mv+dO|6Brj*ih+TVL4u*|$;4?Z zuU%kNex5i9nGWz~WDGetMainWindow (), &w, &h); GLenum status; + char errBuf [100]; std::string resourceZip = std::string(SDL_GetBasePath()) + "test3d.zip", shaderDir = "shaders/", @@ -78,35 +80,24 @@ bool WaterScene::Init() /* Build two framebuffers for reflection and refraction. - Each framebuffer gets a color and depth buffer. + Each framebuffer gets a color and depth-stencil texture. - Also buid two textures, to which the frame buffer's pixel data - will be stored. + The color and depth values will be used by the pixel shader. + The stencil buffer is needed during render to texture. */ glGenFramebuffers (1, &fbReflection); glGenFramebuffers (1, &fbRefraction); - glGenRenderbuffers (1, &cbReflection); - glGenRenderbuffers (1, &cbRefraction); - glGenRenderbuffers (1, &dbReflection); - glGenRenderbuffers (1, &dbRefraction); - glGenTextures (1, &texReflection); glGenTextures (1, &texRefraction); + glGenTextures (1, &texReflecDepth); + glGenTextures (1, &texRefracDepth); glBindFramebuffer (GL_FRAMEBUFFER, fbReflection); - glBindRenderbuffer (GL_RENDERBUFFER, cbReflection); - glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA, w, h); - glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbReflection); - - glBindRenderbuffer(GL_RENDERBUFFER, dbReflection); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dbReflection); - glBindTexture(GL_TEXTURE_2D, texReflection); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA,GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); @@ -114,26 +105,27 @@ bool WaterScene::Init() glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texReflection, 0); + glBindTexture(GL_TEXTURE_2D, texReflecDepth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texReflecDepth, 0); + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, 0); - if(status != GL_FRAMEBUFFER_COMPLETE) + if (status != GL_FRAMEBUFFER_COMPLETE) { - SetError ("error, reflection framebuffer is not complete"); + GLFrameBufferErrorString (errBuf, status); + + SetError ("error, reflection framebuffer is not complete: %s", errBuf); return false; } glBindFramebuffer (GL_FRAMEBUFFER, fbRefraction); - glBindRenderbuffer (GL_RENDERBUFFER, cbRefraction); - glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA, w, h); - glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbRefraction); - - glBindRenderbuffer (GL_RENDERBUFFER, dbRefraction); - glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); - glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dbRefraction); - glBindTexture (GL_TEXTURE_2D, texRefraction); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -141,15 +133,24 @@ bool WaterScene::Init() glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texRefraction, 0); + glFramebufferTexture (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texRefraction, 0); - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindTexture (GL_TEXTURE_2D, texRefracDepth); + glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFramebufferTexture (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texRefracDepth, 0); + + status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + + glBindFramebuffer (GL_FRAMEBUFFER, 0); if (status != GL_FRAMEBUFFER_COMPLETE) { - SetError ("error, refraction framebuffer is not complete"); + GLFrameBufferErrorString (errBuf, status); + + SetError ("error, refraction framebuffer is not complete: %s", errBuf); return false; } @@ -200,14 +201,11 @@ WaterScene::~WaterScene() glDeleteTextures(1, &texReflection); glDeleteTextures(1, &texRefraction); + glDeleteTextures(1, &texReflecDepth); + glDeleteTextures(1, &texRefracDepth); glDeleteFramebuffers(1, &fbReflection); glDeleteFramebuffers(1, &fbRefraction); - - glDeleteRenderbuffers(1, &cbReflection); - glDeleteRenderbuffers(1, &cbRefraction); - glDeleteRenderbuffers(1, &dbReflection); - glDeleteRenderbuffers(1, &dbRefraction); } void WaterScene::UpdateWaterNormals() { @@ -268,6 +266,32 @@ void WaterScene::MakeWave (const vec3 p, const float l) } } } +void WaterScene::CubeBlockWaves () +{ + float x1 = posCube.x - CUBESIZE / 2, x2 = posCube.x + CUBESIZE / 2, + y1 = posCube.y - CUBESIZE / 2, y2 = posCube.y + CUBESIZE / 2, + z1 = posCube.z - CUBESIZE / 2, z2 = posCube.z + CUBESIZE / 2, + + smallestDist2; + + for (int x = 1; x < GRIDSIZE; x++) + { + for(int z = 1; z < GRIDSIZE; z++) + { + if (0 > y1 && 0 < y2) + { + if (gridpoints[x][z].x > x1 && gridpoints[x][z].x < x2 && + gridpoints[x][z].z > z1 && gridpoints[x][z].z < z2) + { + // Cancel all waves at the edge of the cube. + + gridpoints[x][z].y = 0; + } + } + } + } +} + #define SQRT2DIV2 0.707106781186547524400844362104849f void WaterScene::UpdateWater (const float dt) { @@ -289,16 +313,18 @@ void WaterScene::UpdateWater (const float dt) { for(int z=1; z<(GRIDSIZE-1); z++) { - d=gridpoints[x][z].y - gridpoints[x-1][z].y; + // The forces are composed of the y level differences between points: + + d=gridpoints[x][z].y - gridpoints[x-1][z].y; gridforces[x][z]-=d; gridforces[x-1][z]+=d; - d=gridpoints[x][z].y - gridpoints[x+1][z].y; + d=gridpoints[x][z].y - gridpoints[x+1][z].y; gridforces[x][z]-=d; gridforces[x+1][z]+=d; - d=gridpoints[x][z].y - gridpoints[x][z-1].y; + d=gridpoints[x][z].y - gridpoints[x][z-1].y; gridforces[x][z]-=d; gridforces[x][z-1]+=d; - d=gridpoints[x][z].y - gridpoints[x][z+1].y; + d=gridpoints[x][z].y - gridpoints[x][z+1].y; gridforces[x][z]-=d; gridforces[x][z+1]+=d; d=gridpoints[x][z].y - gridpoints[x-1][z+1].y; d*=SQRT2DIV2; @@ -312,6 +338,9 @@ void WaterScene::UpdateWater (const float dt) d=gridpoints[x][z].y - gridpoints[x+1][z-1].y; d*=SQRT2DIV2; gridforces[x][z]-=d; gridforces[x+1][z-1]+=d; + + // friction: + // gridforces[x][z] -= gridspeeds[x][z]; } } @@ -319,21 +348,20 @@ void WaterScene::UpdateWater (const float dt) if (ft > 1.0f) ft = 1.0f; - // friction / viscosity - float u = (float)exp(250.0f * dt * log(0.99f)); + float u = (float)exp (-2.5 * dt); for(int x=0; x Date: Wed, 19 Aug 2015 23:52:10 +0200 Subject: [PATCH 10/10] bumped version to 1.3.0 --- notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes.txt b/notes.txt index d6ebd9a..b5ad905 100644 --- a/notes.txt +++ b/notes.txt @@ -1,4 +1,4 @@ -Game templates version 1.2.0 +Game templates version 1.3.0 [test3d]