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%)
diff --git a/bin/test3d.zip b/bin/test3d.zip
index 019917a..6ccebb2 100644
Binary files a/bin/test3d.zip and b/bin/test3d.zip differ
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/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]
diff --git a/server.cbp b/server.cbp
index 4784533..223e3ad 100644
--- a/server.cbp
+++ b/server.cbp
@@ -41,6 +41,8 @@
+
+
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
-#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);
+ }
}
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/manager/manager.cpp b/src/manager/manager.cpp
index d59f0cb..d19afb9 100644
--- a/src/manager/manager.cpp
+++ b/src/manager/manager.cpp
@@ -29,6 +29,7 @@
#include
#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/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/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..189cfb3 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,35 @@ GLuint CreateShader(const std::string& source, int type)
return 0;
}
- GLint result = GL_FALSE;
+ GLint result;
int logLength;
- GLuint shader = glCreateShader(type);
+ 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)
{
- glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
+ // Error occurred, get compile log:
+ 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)
- char *errorString = new char[logLength];
- glGetShaderInfoLog(shader, logLength, NULL, errorString);
- SetError ("Error compiling shader: %s", errorString);
- delete[] errorString;
+ SetError ("Error compiling fragment shader: %s", errorString);
- glDeleteShader(shader);
+ delete [] errorString;
+
+ glDeleteShader (shader);
return 0;
}
@@ -63,33 +78,42 @@ 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);
- glGetProgramiv(program, GL_LINK_STATUS, &result);
- if(result!=GL_TRUE)
+ glAttachShader (program, vertexShader);
+ glAttachShader (program, fragmentShader);
+
+ glLinkProgram (program);
+
+ 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/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/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
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 cb205fb..7367bdb 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,12 @@ 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.
+ This makes the rendered mesh a bit larger than the original.
+ */
+
if(pMeshData->subsets.find(id) == pMeshData->subsets.end())
{
SetError ("cannot render %s, no such subset", id.c_str());
@@ -129,10 +141,10 @@ 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++)
+ // 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++)
{
@@ -144,12 +156,12 @@ 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++)
+ 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++)
@@ -178,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);
@@ -222,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);
@@ -249,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);
@@ -271,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);
@@ -285,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/test3d/water.cpp b/src/test3d/water.cpp
index d405410..d87902e 100644
--- a/src/test3d/water.cpp
+++ b/src/test3d/water.cpp
@@ -35,11 +35,12 @@
#define VIEW_ANGLE 45.0f
#define NEAR_VIEW 0.1f
#define FAR_VIEW 1000.0f
+#define CUBESIZE 2.0f
WaterScene::WaterScene (App *pApp) : Scene(pApp),
- fbReflection(0), cbReflection(0), dbReflection(0), texReflection(0),
- fbRefraction(0), cbRefraction(0), dbRefraction(0), texRefraction(0),
+ fbReflection(0), texReflection(0), texReflecDepth(0),
+ fbRefraction(0), texRefraction(0), texRefracDepth(0),
shaderProgramWater(0),
timeDrop(0),
@@ -56,8 +57,8 @@ WaterScene::WaterScene (App *pApp) : Scene(pApp),
{
for(int z=0; zGetMainWindow (), &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; x0) return ((*this)/l);
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); }
@@ -120,8 +134,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 +162,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 +170,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();