Repository: MauriceGit/Water_Simulation Branch: master Commit: 713c72e4d31a Files: 33 Total size: 136.7 KB Directory structure: gitextract_532xa9lh/ ├── LICENSE ├── README.md └── src/ ├── Makefile ├── Makefile.common ├── Makefile.depend ├── colorFragmentShader.frag ├── colorVertexShader.vert ├── imageLoader.c ├── imageLoader.h ├── io.c ├── io.h ├── logic.c ├── logic.h ├── main.c ├── particle.c ├── particle.h ├── scene.c ├── scene.h ├── stringOutput.c ├── stringOutput.h ├── terrain.c ├── terrain.h ├── textureDepthFragmentShader.frag ├── textureFragmentShader.frag ├── textureVertexShader.vert ├── types.h ├── vector.c ├── vector.h ├── water ├── water.c ├── water.h ├── waterFragmentShader.frag └── waterVertexShader.vert ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE ================================================ Copyright (c) 2015, 2016 Maurice Tollmien Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: README.md ================================================ # Water-Simulation with Realtime Reflections/Refractions from the Surface This project consists of several smaller projects joined together. Everything is done completely from scratch. No external libraries or dependencies (except basic OpenGL) are needed to run this simulation. The final result looks like that: ![Water-Simulation](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished3.png "Water-Simulation with reflections/refractions") ## **Water Simulation** The water simulation itself is a pressure based height field. The water's surface is divided into a small grid of points. Each height represents the pressure at that point. For each time step the pressure is divided and continued on to the next water point. The calculation itself is similar to image processing calculations, where a kernel over each pixel calculates the color at that pixel. A height field water simulation looks very real for smaller waves and distorted water surfaces. But because of using a height-field (real time efficiency and simplicity to implement) there is no possibility of calculating single drops or any kind of detachment of waterbodies from the surface. Also no overlapping waves or such things are possible. Example with random displacement added to the water's surface, creating very small waves (distortion): ![Water-Distortion](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished6.png "Small distortions") Example with some small spreading waves: ![Spreading waves](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished7.png "Spreading waves") Example with waves bouncing back from the shore: ![Bouncing waves](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished1.png "Waves bouncing from the shore") ## **Reflections / Refractions (Screenspace)** Both the reflection and refraction of the water's surface is calculated in screen space with OpenGL fragment shaders. The main benefit of using screenspace reflections/refractions is, that it takes a constant time to calculate and doesn't depend on the complexity of the scene. Another benefit is, that both the reflection and refraction can be calculated using the exact same calculations. - For each frame, two textures (color-texture and depth-texture) are created from the point of view and provided to the OpenGL fragment shader. - For each pixel, the position of each reflection/refraction-point is provided in world-coordinates to the fragment shader. - A step-size is determined (could also be constant). - For each step, the reflection-vector is scaled with the determinded step-size and transformed into screenspace. We now have two vectors. One is the reflection-vector in world coordinates and the same one transformed into screen space. - Because we look at the same scene which is saved into the texture, we can now sample the depth-texture and get the depth of the scene at the point of the scaled reflection-vector. - We continue the scaling of the reflection-vector until the depth of the sampled depth-texture is smaller than the z-coordinate (depth) of the reflection-vector in world coordinates. In this case we know, that we hit something which should be displayed as the reflection for the original fragment. - We can then take the transformed reflection-vector and sample the color texture. The result should be the color of the reflection. We take that color and are finished. Positive features: Works in real time looks good most of the time. Negative features: Actually takes longer to calculate, if there are no reflections, is not always correct, not defined for situations where the reflection goes outside the screenspace and can only reflect objects which are on the screen! (Also there are incorrect reflections if there is an object between the camera and the water's surface.) Water refraction: ![Refraction](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished2.png "Water-Refraction looking good!") Reflection and refraction with no waves at all: ![No Wave-Reflection](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished5.png "Water-Reflection, no waves") Refraction and Reflection of smaller waves from above: ![Small waves](https://github.com/MauriceGit/Water_Simulation/blob/master/Screenshots/finished4.png "Water-Refraction/Reflection with small waves") ## **Terrain Modelling** The terrain is modelled using a 2D-Perlin-Noise-function (implemented from scratch!). It overlays different frequences of sinus and cosinus waves. The perlin-noise height field is then textured based on the current height (Overlapping of different textures). The mountain like hill is added by adding a gauss function to the perlin-noise output. The same goes for the valley where the water is. ## **Install && Run** I only tested and ran this simulation on a debian-based Linux OS (Ubuntu, Mint, ...). It should run on other machines as well but is not tested. ### **Requirements** The following system-attributes are required for running this simulation: - A graphics card supporting OpenGL version 3.3 (For the shaders). - Unix-Libraries: xorg-dev, freeglut3-dev and mesa-common-dev ### **Running** Compiling and running is pretty straight forward. - make - ./water While the simulation runs, you can move around (always looking to the center!) with your mouse (left-klick and move). Initializing a random movement (choppy water) is done with 'r'. Creating one/several waves can be done by pressing 'n'. ================================================ FILE: src/Makefile ================================================ # Quelldateien SRCS = imageLoader.c vector.c main.c scene.c io.c water.c terrain.c logic.c stringOutput.c # ausfuehrbares Ziel TARGET = water # Ist libz verfgbar? HAVE_LIBZ = yes # Basis-Makefile einbinden -include ./Makefile.common # Precompiler flags # Pfad der Schnittstelle des ImageLoaders hinzufuegen CPPFLAGS_COMMON += -I$(IMGLOADER_DIR)/include # Linker flags # Pfad der ImageLoader-Bibliothek hinzufuegen LDFLAGS_COMMON += -L$(IMGLOADER_DIR)/lib # Wenn libz verfuegbar ist, muessen wir sie mit einlinken, um die # Bibliothek auch zum Laden von PNG-Bildern verwenden zu koennen. ifeq ($(HAVE_LIBZ),yes) LDLIBS += -lz endif .PHONY: distcleanimageloader # TARGETS # Regel zur Erstellung der ImageLoader-Bibliothek $(IMGLOADER_DIR)/lib/$(IMGLOADER_LIB): (cd $(IMGLOADER_DIR) && ./configure) $(MAKE) -C $(IMGLOADER_DIR) # Vollstaendiges Aufraeumen beinhaltet auch Aufraeumen des ImageLoaders distclean: distcleanimageloader # Regel zum Aufraeumen des ImageLoaders distcleanimageloader: if [ -f $(IMGLOADER_DIR)/Makefile ]; then $(MAKE) -C $(IMGLOADER_DIR) HAVE_LIBZ=$(HAVE_LIBZ) distclean; fi ================================================ FILE: src/Makefile.common ================================================ # Objektdateien OBJS = $(SRCS:.c=.o) # Compiler CC = gcc # Precompiler flags CPPFLAGS_LINUX = CPPFLAGS_LINUX64 = CPPFLAGS_MACOSX = -DMACOSX CPPFLAGS_COMMON = -I./ CPPFLAGS = $(CPPFLAGS_COMMON) $(CPPFLAGS_$(OS)) # Compiler flags CFLAGS_LINUX = CFLAGS_LINUX64 = CFLAGS_MACOSX = CFLAGS_COMMON = -Wextra -ansi CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_$(OS)) # Linker LD = gcc # Linker flags LDFLAGS_LINUX = -L/usr/X11R6/lib -L/usr/lib LDFLAGS_LINUX64 = -L/usr/X11R6/lib64 LDFLAGS_MACOSOX = LDFLAGS_COMMON = LDFLAGS = $(LDFLAGS_COMMON) $(LDFLAGS_$(OS)) # Linker libraries XLIBS = -lXmu -lXi -lX11 GLLIBS = -lglut -lGLU -lGL LDLIBS_LINUX = $(GLLIBS) #$(XLIBS) LDLIBS_LINUX64 = $(GLLIBS) #$(XLIBS) LDLIBS_MACOSX = -framework OpenGL -framework GLUT -framework Foundation LDLIBS_COMMON = -lm LDLIBS = $(LDLIBS_COMMON) $(LDLIBS_$(OS)) # welches Betriebssystem? ifeq ($(findstring Linux,$(shell uname -s)),Linux) OS = LINUX ifeq ($(shell uname -m),x86_64) OS = LINUX64 endif else ifeq ($(shell uname -s),Darwin) OS = MACOSX endif endif # Debugging-Informationen aktivieren DEBUG = yes # Wenn Debugging-Informationen aktiviert werden sollen, entsprechende # Praeprozessorflags setzen ifeq ($(DEBUG),yes) CPPFLAGS_COMMON+=-g -DDEBUG endif .SUFFIXES: .o .c .PHONY: all clean distclean depend # TARGETS all: depend $(TARGET) doc: doxygen ../common/Doxyfile # Linken des ausfuehrbaren Programms $(TARGET): $(OBJS) $(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(TARGET) # Kompilieren der Objektdateien %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $*.o $*.c # einfaches Aufraeumen clean: rm -f $(TARGET) rm -f $(OBJS) # alles loeschen, was erstellt wurde distclean: clean rm -f *~ rm -f Makefile.depend rm -rf doc rm -rf doxygen.log # Abhaengigkeiten automatisch ermitteln depend: @rm -f Makefile.depend @echo -n "building Makefile.depend ... " @$(foreach SRC, $(SRCS), ( $(CC) $(CPPFLAGS) $(SRC) -MM -g0 ) 1>> Makefile.depend;) @echo "done" # zusaetzliche Abhaengigkeiten einbinden -include Makefile.depend ================================================ FILE: src/Makefile.depend ================================================ imageLoader.o: imageLoader.c imageLoader.h vector.o: vector.c stringOutput.h types.h main.o: main.c io.h scene.h types.h scene.o: scene.c stringOutput.h scene.h types.h logic.h water.h terrain.h \ vector.h io.o: io.c io.h scene.h types.h logic.h water.h terrain.h vector.h \ imageLoader.h water.o: water.c water.h types.h terrain.h particle.h logic.h vector.h terrain.o: terrain.c terrain.h types.h logic.h vector.h logic.o: logic.c stringOutput.h logic.h types.h vector.h scene.h water.h \ terrain.h stringOutput.o: stringOutput.c stringOutput.h ================================================ FILE: src/colorFragmentShader.frag ================================================ #version 330 in vec3 color; out vec4 Color; uniform vec3 colorIn; void main(){ Color = vec4(colorIn, 1.0); } ================================================ FILE: src/colorVertexShader.vert ================================================ #version 330 layout (location = 0) in vec3 vertPos; uniform mat4 viewMatrix, projMatrix; void main(){ gl_Position = projMatrix * viewMatrix * vec4(vertPos, 1.0); } ================================================ FILE: src/imageLoader.c ================================================ #include #include #include #include /* ---- Eigene Header einbinden ---- */ #include "imageLoader.h" int error(FILE * f, char * name, char * errorMessage) { printf("%s: %s.\n", errorMessage, name); fclose(f); return 0; } /* Loads image for texture creation.*/ int imageLoad(char *filename, Image *image) { FILE *file; unsigned long size; /* size of the image in bytes.*/ unsigned long i; /* standard counter.*/ unsigned short int planes; /* number of planes in image (must be 1) */ unsigned short int bpp; /* number of bits per pixel (must be 24)*/ char temp; /* used to convert bgr to rgb color.*/ image->sizeX = 0; image->sizeY = 0; /* make sure the file is there*/ if ((file = fopen(filename, "rb")) == NULL) return error(file, "File Not Found", filename); /* seek through the bmp header, up to the width/height:*/ fseek(file, 18, SEEK_CUR); /* read the width*/ if ((i = fread(&image->sizeX, 4, 1, file)) != 1) return error(file, "Error reading width from", filename); printf("Width of %s: %lu\n", filename, image->sizeX); /* read the height */ if ((i = fread(&image->sizeY, 4, 1, file)) != 1) return error(file, "Error reading height from", filename); printf("Height of %s: %lu\n", filename, image->sizeY); /* calculate the size (assuming 24 bits or 3 bytes per pixel).*/ size = image->sizeX * image->sizeY * 3; /* read the planes*/ if ((fread(&planes, 2, 1, file)) != 1) return error(file, "Error reading planes from", filename); if (planes != 1) return error(file, "Planes from file is not 1", filename); /* read the bpp */ if ((i = fread(&bpp, 2, 1, file)) != 1) return error(file, "Error reading bpp from", filename); if (bpp != 24) return error(file, "Bpp from file is not 24\n", filename); /* seek past the rest of the bitmap header.*/ fseek(file, 24, SEEK_CUR); /* read the data. */ image->data = malloc(size); if (image->data == NULL) return error(file, "Error allocating memory for color-corrected image data", filename); if ((i = fread(image->data, size, 1, file)) != 1) return error(file, "Error reading image data from", filename); for (i=0;idata[i]; image->data[i] = image->data[i+2]; image->data[i+2] = temp; } fclose(file); return 1; } ================================================ FILE: src/imageLoader.h ================================================ #ifndef __IMAGE_H__ #define __IMAGE_H__ #define __DEBUG_GL_H__ /** * @file * Programmlogik und Datenhaltung * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #include #include typedef struct { long unsigned int sizeX, sizeY; unsigned char * data; } Image; int imageLoad(char *filename, Image *image); #endif ================================================ FILE: src/io.c ================================================ /** * @file * Hier sind alle CallBack-Funktionen * * @author Maurice Tollmien, Tilman Nedele */ /* ---- System Header einbinden ---- */ #include #include #include #include #ifdef MACOSX #include #else #include #endif /* ---- Eigene Header einbinden ---- */ #include "io.h" #include "scene.h" #include "logic.h" #include "water.h" #include "terrain.h" #include "vector.h" #include "imageLoader.h" /* ---- Eigene Funktionen ---- */ /* Texturen und Framebuffer */ GLuint G_fboCam, G_fboRefl, G_fboRefr, G_TexCamera, G_TexCameraDepth, G_TexReflection, G_TexRefraction, G_TexImageGrass, G_TexImageSand, G_TexImageCaustics, G_TexImageRocks, G_TexImageSnow, G_TexImageForest, G_TexImageTundra; /* Shader-ID's */ GLuint G_ShaderID, G_ShaderIDSimple, G_ShaderColor, G_ShaderIDSimpleD; /* Geometrie-Buffer */ GLuint G_arrayBuffer, G_TexCube, G_cubeBuffer, G_SurfaceBuffer, G_WaterBuffer, G_WaterBufferIndex, G_ObjectsBuffer, G_TerrainBuffer, G_TerrainBufferIndex, G_CausticsBuffer; /* Cube-Map */ GLuint G_TexCubeFront, G_TexCubeBack, G_TexCubeBottom, G_TexCubeTop, G_TexCubeLeft, G_TexCubeRight; /* Shader-Variablen */ GLuint G_projMatrixLoc, G_viewMatrixLoc, G_sampler2dLoc, G_samplerDepth2dLoc, G_cameraPosLoc, G_colorIn, G_samplerCubeLoc; int view = 1; int G_Width = 1024; int G_Height = 1024; int G_fullScreen = 1; GLfloat G_data[] = { -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0 }; float G_Surface[] = { -75, 0.0, -75, -75, 0.0, 75, 75, 0.0, 75, -75, 0.0, -75, 75, 0.0, 75, 75, 0.0, -75 }; GLfloat G_Objects[] = { -30.0, -30.0, -30.0, 30.0, -30.0, -30.0, 30.0, 30.0, -30.0, -30.0, -30.0, -30.0, 30.0, 30.0, -30.0, -30.0, 30.0, -30.0 }; float G_points[] = { -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, 100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, 100.0f, 100.0f, -100.0f, -100.0f, 100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, -100.0f, 100.0f, -100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, -100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f, 100.0f, 100.0f, -100.0f, -100.0f, 100.0f, -100.0f, -100.0f, -100.0f, -100.0f, 100.0f, 100.0f, -100.0f, 100.0f }; /** * Timer-Callback. * Initiiert Berechnung der aktuellen Position und Farben und anschliessendes * Neuzeichnen, setzt sich selbst erneut als Timer-Callback. * @param lastCallTime Zeitpunkt, zu dem die Funktion als Timer-Funktion * registriert wurde (In). */ static void cbTimer (int lastCallTime) { /* Seit dem Programmstart vergangene Zeit in Millisekunden */ int thisCallTime = glutGet (GLUT_ELAPSED_TIME); /* Seit dem letzten Funktionsaufruf vergangene Zeit in Sekunden */ double interval = (double) (thisCallTime - lastCallTime) / 1000.0f; calcTimeRelatedStuff(interval); /* Wieder als Timer-Funktion registrieren */ glutTimerFunc (1000 / TIMER_CALLS_PS, cbTimer, thisCallTime); /* Neuzeichnen anstossen */ glutPostRedisplay (); } /** * Setzen der Projektionsmatrix. * Setzt die Projektionsmatrix unter Berücksichtigung des Seitenverhaeltnisses * des Anzeigefensters, sodass das Seitenverhaeltnisse der Szene unveraendert * bleibt und gleichzeitig entweder in x- oder y-Richtung der Bereich von -1 * bis +1 zu sehen ist. * @param aspect Seitenverhaeltnis des Anzeigefensters (In). */ static void setProjection (GLdouble aspect) { /* Nachfolgende Operationen beeinflussen Projektionsmatrix */ glMatrixMode (GL_PROJECTION); /* Matrix zuruecksetzen - Einheitsmatrix laden */ glLoadIdentity (); { /* perspektivische Projektion */ gluPerspective (90.0, /* Oeffnungswinkel */ aspect, /* Seitenverhaeltnis */ 0.01, /* nahe ClipPIEng-Ebene */ 1000.0 /* ferne ClipPIEng-Ebene */ ); } } static void drawColoredQuad(double r, double g, double b) { glDisable(GL_CULL_FACE); glUseProgram(G_ShaderColor); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderColor, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderColor, "viewMatrix"), 1, GL_FALSE, &mv[0]); GLfloat color[] = {r, g, b}; GLfloat cam[] = {getCameraPosition(0), getCameraPosition(1), getCameraPosition(2)}; glUniform3fv(glGetUniformLocation(G_ShaderColor, "colorIn"), 1, color); glUniform3fv(glGetUniformLocation(G_ShaderColor, "cameraPos"), 1, cam); glBindBuffer (GL_ARRAY_BUFFER, G_ObjectsBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), 0); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glBindBuffer (GL_ARRAY_BUFFER, 0); glUseProgram(0); glEnable(GL_CULL_FACE); } static void drawSimpleStuff(GLuint colorTex, int fromX, int fromY, int width, int height) { glUseProgram(G_ShaderIDSimple); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (fromX, fromY, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (90.0, 1, 5.1, 1000.0 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (0,0,1, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, colorTex); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "viewMatrix"), 1, GL_FALSE, &mv[0]); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texsampler"), 0); glBindBuffer (GL_ARRAY_BUFFER, G_arrayBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 3*sizeof(float)); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer (GL_ARRAY_BUFFER, 0); glUseProgram(0); } static void drawSimpleStuffShader(GLuint shader, GLuint colorTex, int fromX, int fromY, int width, int height) { glUseProgram(shader); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (fromX, fromY, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (90.0, 1, 5.1, 1000.0 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (0,0,1, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, colorTex); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "viewMatrix"), 1, GL_FALSE, &mv[0]); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texsampler"), 0); glBindBuffer (GL_ARRAY_BUFFER, G_arrayBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 3*sizeof(float)); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer (GL_ARRAY_BUFFER, 0); glUseProgram(0); } void drawTerrainComplete(void) { glUseProgram(G_ShaderIDSimple); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, G_TexImageGrass); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, G_TexImageSand); glActiveTexture(GL_TEXTURE0+2); glBindTexture(GL_TEXTURE_2D, G_TexImageForest); glActiveTexture(GL_TEXTURE0+3); glBindTexture(GL_TEXTURE_2D, G_TexImageRocks); glActiveTexture(GL_TEXTURE0+4); glBindTexture(GL_TEXTURE_2D, G_TexImageSnow); glActiveTexture(GL_TEXTURE0+5); glBindTexture(GL_TEXTURE_2D, G_TexImageTundra); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderIDSimple, "viewMatrix"), 1, GL_FALSE, &mv[0]); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texSand") , 1); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texGrass"), 0); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texForest"), 2); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texRocks"), 3); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texSnow"), 4); glUniform1i(glGetUniformLocation(G_ShaderIDSimple, "texTundra"), 5); /* Wasser-Normalen für eigene Caustics-Berechnungen */ glBindBuffer (GL_ARRAY_BUFFER, G_CausticsBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getTerrainCaustics())*TERRAIN_SIZE*TERRAIN_SIZE, getTerrainCaustics(), GL_STREAM_DRAW); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 5*sizeof(GLfloat)); /* Offset in X und Z-Richtung eventuell hier in die Shader übergeben... */ glBindBuffer (GL_ARRAY_BUFFER, G_TerrainBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 3*sizeof(GLfloat)); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 5*sizeof(GLfloat)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, G_TerrainBufferIndex); glDrawElements(GL_TRIANGLES, TERRAIN_SIZE*TERRAIN_SIZE*2*3, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glDisableVertexAttribArray(3); glUseProgram(0); } void drawSceneToTexture(GLuint tex, GLfloat ex, GLfloat ey, GLfloat ez, GLfloat cx, GLfloat cy, GLfloat cz) { glBindFramebuffer(GL_FRAMEBUFFER, tex); glClearColor(0.0, 1.0, 1.0, 0.0); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport (0, 0, G_Width, G_Height); setProjection (1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt ( ex, ey, ez, cx, cy, cz, 0.0, 1.0, 0.0); glDisable(GL_TEXTURE_2D); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { printf ("Framebuffer ist nicht korrekt! 4\n"); } /*drawSides();*/ drawTerrainComplete(); } void allocateMemoryStuff(GLuint * texID, GLuint * fbo) { glGenTextures(1, texID); glBindTexture(GL_TEXTURE_2D, *texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);*/ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /*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_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, G_Width, G_Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glGenFramebuffers(1, fbo); glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texID, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void allocateMemoryStuffDepth(GLuint * texID, GLuint * texID2, GLuint * fbo) { glGenTextures(1, texID); glBindTexture(GL_TEXTURE_2D, *texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, G_Width, G_Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glGenTextures(1, texID2); glBindTexture(GL_TEXTURE_2D, *texID2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, G_Width, G_Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); glGenFramebuffers(1, fbo); glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, *texID2, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void loadCubeSide(GLuint * texID, GLenum side) { /*glBindTexture(GL_TEXTURE_CUBE_MAP, *texID);*/ glTexImage2D(side, 0, GL_RGBA8, G_Width, G_Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); } void appendTexToFB(GLuint * fbo, GLuint * texID, GLenum side) { glGenFramebuffers(1, fbo); glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, side, *texID, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void allocateMemoryStuffCube(GLuint * texID) { glActiveTexture (GL_TEXTURE0); glGenTextures(1, texID); glBindTexture(GL_TEXTURE_CUBE_MAP, *texID); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); /* front */ loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_POSITIVE_Z); /* back */ loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y); /* bottom */ loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_POSITIVE_Y); /* top */ loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_X); /* left */ loadCubeSide(texID, GL_TEXTURE_CUBE_MAP_POSITIVE_X); /* right */ appendTexToFB(&G_TexCubeFront, texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); appendTexToFB(&G_TexCubeBack, texID, GL_TEXTURE_CUBE_MAP_POSITIVE_Z); appendTexToFB(&G_TexCubeBottom,texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y); appendTexToFB(&G_TexCubeTop, texID, GL_TEXTURE_CUBE_MAP_POSITIVE_Y); appendTexToFB(&G_TexCubeLeft, texID, GL_TEXTURE_CUBE_MAP_NEGATIVE_X); appendTexToFB(&G_TexCubeRight, texID, GL_TEXTURE_CUBE_MAP_POSITIVE_X); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { printf ("Framebuffer ist nicht korrekt 1!\n"); } glBindFramebuffer(GL_FRAMEBUFFER, 0); } void renderFBToCubeTexture(GLuint * fbo, GLenum side, double vX, double vY, double vZ) { /*==================================================================*/ /* Eine Seite für die Cube-Textur rendern */ /*==================================================================*/ glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glClearColor(0.0, 1.0, 1.0, 0.0); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport (0, 0, G_Width, G_Height); setProjection(1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (0, 0, 0, vX, vY, vZ, 0.0, fabs(vY) > 0.8 ? 0.0 : 1.0, vY > 0.8 ? 1.0 : (vY < -0.8 ? -1.0 : 0.0)); glDisable(GL_TEXTURE_2D); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { printf ("Framebuffer ist nicht korrekt! 2\n"); } /*drawColoredQuad(1,1,1);*/ /*drawSides();*/ /* RAUS, WEIL EIGENTLICH NUR DIE ENTFERNTE UMGEBUNG HIER WAHRGENOMMEN WERDEN SOLL UND NICHT DIE KONKRETEN, DYNAMISCHEN OBJEKTE DER SCENE!!!!!!! */ /*drawTerrainComplete();*/ } /** * Zeichen-Callback. * Loescht die Buffer, ruft das Zeichnen der Szene auf und tauscht den Front- * und Backbuffer. */ static void cbDisplay (void) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.0, 1.0, 1.0, 0.0); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /*==================================================================*/ /* Textur mit Kamera-Perspektive */ /*==================================================================*/ drawSceneToTexture(G_fboCam, getCameraPosition(0), getCameraPosition(1), getCameraPosition(2), 0.0, 0.0, 0.0); /*==================================================================*/ /* Textur mit Reflection-Perspektive */ /*==================================================================*/ /*drawSceneToTexture(G_fboRefl, 0.0, 0.0, 0.0, getCameraPosition(0)+(2*-getCameraPosition(0)), getCameraPosition(1)+(2*-getCameraPosition(1))+2*getCameraPosition(1), getCameraPosition(2)+(2*-getCameraPosition(2)));*/ /*==================================================================*/ /* Kamera-Textur rendern. */ /*==================================================================*/ if (0) { drawSimpleStuff(G_fboCam, 0, G_Height/2, G_Width/2, G_Height/2); } if (0) { drawSimpleStuffShader(G_ShaderIDSimpleD, G_TexCameraDepth, 0, 0, G_Width/2, G_Height/2); } /*==================================================================*/ /* Reflection-Textur rendern */ /*==================================================================*/ if (0) { drawSimpleStuff(G_TexReflection, G_Width/2, G_Height/2, G_Width/2, G_Height/2); } /*==================================================================*/ /* Spiegelfläche mit korrektem dynamischen Environment-Mapping (Reflection + Refraction) */ /*==================================================================*/ if (0) { glUseProgram(G_ShaderID); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (0, 0, G_Width/2, G_Height/2); setProjection (1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (getCameraPosition(0), getCameraPosition(1), getCameraPosition(2), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glEnable(GL_TEXTURE_CUBE_MAP); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, G_TexCube); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderID, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderID, "viewMatrix"), 1, GL_FALSE, &mv[0]); glUniform1i(G_sampler2dLoc, 0); GLfloat cam_pos[] = {getCameraPosition(0), getCameraPosition(1), getCameraPosition(2)}; glUniform3fv(glGetUniformLocation(G_ShaderID, "cameraPos"), 1, cam_pos); glBindBuffer (GL_ARRAY_BUFFER, G_WaterBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getWaterList())*WORLD_SIZE*WORLD_SIZE, getWaterList(), GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat)+1*sizeof(GLint), 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat)+1*sizeof(GLint), 5*sizeof(GLfloat)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, G_WaterBufferIndex); /* Wasser. */ glDrawElements(GL_TRIANGLES, WORLD_SIZE*WORLD_SIZE*2*3, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisable(GL_TEXTURE_CUBE_MAP); glDisable(GL_TEXTURE_2D); glUseProgram(0); /*drawSides();*/ drawTerrainComplete(); } /*==================================================================*/ /* Spiegelfläche mit Screenspace-Reflections */ /*==================================================================*/ if (1) { int toX = G_fullScreen ? G_Width : G_Width/2, toZ = G_fullScreen ? G_Height : G_Height/2; glUseProgram(G_ShaderID); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (0, 0, toX, toZ); setProjection (1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (getCameraPosition(0), getCameraPosition(1), getCameraPosition(2), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, G_TexCamera); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, G_TexCameraDepth); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_CUBE_MAP, G_TexCube); GLfloat mp[16], mv[16]; glGetFloatv(GL_PROJECTION_MATRIX, mp); glGetFloatv(GL_MODELVIEW_MATRIX, mv); glUniformMatrix4fv(glGetUniformLocation(G_ShaderID, "projMatrix"), 1, GL_FALSE, &mp[0]); glUniformMatrix4fv(glGetUniformLocation(G_ShaderID, "viewMatrix"), 1, GL_FALSE, &mv[0]); glUniform1i(G_sampler2dLoc, 1); glUniform1i(G_samplerDepth2dLoc, 0); glUniform1i(G_samplerCubeLoc, 2); GLfloat cam_pos[] = {getCameraPosition(0), getCameraPosition(1), getCameraPosition(2)}; glUniform3fv(glGetUniformLocation(G_ShaderID, "cameraPos"), 1, cam_pos); /*glBindBuffer (GL_ARRAY_BUFFER, G_TerrainBuffer); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0);*/ glBindBuffer (GL_ARRAY_BUFFER, G_WaterBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getWaterList())*WORLD_SIZE*WORLD_SIZE, getWaterList(), GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat)+1*sizeof(GLint), 0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat)+1*sizeof(GLint), 5*sizeof(GLfloat)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, G_WaterBufferIndex); /* Wasser. */ glDrawElements(GL_TRIANGLES, WORLD_SIZE*WORLD_SIZE*2*3, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glUseProgram(0); /*drawSides();*/ drawTerrainComplete(); drawFPS(); } /*==================================================================*/ /* Landschaft aus Perlin-Noise. */ /*==================================================================*/ if (!G_fullScreen) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (G_Width/2, G_Height/2, G_Width/2, G_Height/2); setProjection (1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (getCameraPosition(0), getCameraPosition(1), getCameraPosition(2), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); drawTerrainComplete(); } /*==================================================================*/ /* Die Normale Scene auf der rechten Seite rendern. Echte Polygone etc. */ /*==================================================================*/ if (0) { glUseProgram(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport (0, G_Height/2, G_Width/2, G_Height/2); setProjection (1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (getCameraPosition(0), getCameraPosition(1), getCameraPosition(2), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glDisable(GL_TEXTURE_2D); drawSides(); drawWaterSurface(); } /* Alles fertig. */ glutSwapBuffers (); } /** * Callback fuer Tastendruck. * Ruft Ereignisbehandlung fuer Tastaturereignis auf. * @param key betroffene Taste (In). * @param x x-Position der Maus zur Zeit des Tastendrucks (In). * @param y y-Position der Maus zur Zeit des Tastendrucks (In). */ void cbKeyboard (unsigned char key, int x, int y) { switch (key) { case 'q': case 'Q': case ESC: exit (0); break; case 'r': case 'R': /*initGame ();*/ setRandomize(); break; case 'h': case 'H': setHelpStatus(!getHelpStatus()); break; case '+': incQuadCount(); break; case '-': decQuadCount(); break; case 'n': case 'N': pushSomeWaterDown(); break; case 'w': case 'W': toggleWaterMovement(); break; case 'm': case 'M': toggleSpheresMoving (); break; case 'p': case 'P': toggleParticleFreeze (); break; case 'f': case 'F': G_fullScreen = !G_fullScreen; break; case 's': case 'S': toggleShadows (); break; case 'k': case 'K': printf ("k recognized.\n"); startMovingBall (); break; case 'v': case 'V': view = !view; break; } } /* Spezialtasten-Druck-Callback - wird ausgefuehrt, wenn Spezialtaste * (F1 - F12, Links, Rechts, Oben, Unten, Bild-Auf, Bild-Ab, Pos1, Ende oder * Einfuegen) gedrueckt wird */ void cbSpecial (int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: break; case GLUT_KEY_RIGHT: break; case GLUT_KEY_UP: setKey (1, 1); break; case GLUT_KEY_DOWN: setKey(0,1); break; case GLUT_KEY_F1: toggleWireframeMode(); break; case GLUT_KEY_F2: setLightStatus(!getLightStatus()); break; case GLUT_KEY_F3: setTextureStatus(!getTextureStatus()); break; case GLUT_KEY_F4: break; case GLUT_KEY_F5: break; case GLUT_KEY_F6: break; case GLUT_KEY_F7: break; case GLUT_KEY_F8: break; } } /* Wird aufgerufen, wenn eine Spezialtaste wieder losgelassen wird1 */ void cbUpSpecial (int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: break; case GLUT_KEY_RIGHT: break; case GLUT_KEY_UP: setKey (1,0); break; case GLUT_KEY_DOWN: setKey (0,0); break; } } /** * Verarbeitung eines Mausereignisses. * Durch Bewegung der Maus bei gedrueckter Maustaste kann die aktuelle * Zeichenfarbe beeinflusst werden. * Falls Debugging aktiviert ist, wird jedes Mausereignis auf stdout * ausgegeben. * @param x x-Position des Mauszeigers zum Zeitpunkt der Ereignisausloesung. * @param y y-Position des Mauszeigers zum Zeitpunkt der Ereignisausloesung. * @param eventType Typ des Ereignisses. * @param button ausloesende Maustaste (nur bei Ereignissen vom Typ mouseButton). * @param buttonState Status der Maustaste (nur bei Ereignissen vom Typ mouseButton). */ static void handleMouseEvent (int x, int y, CGMouseEventType eventType, int button, int buttonState) { switch (eventType) { case mouseButton: switch (button) { case GLUT_LEFT_BUTTON: setMouseEvent(MOVE,x,y); break; case GLUT_RIGHT_BUTTON: setMouseEvent(ZOOM,x,y); break; default: break; } break; default: break; } if (buttonState) setMouseEvent(NONE,x,y); } /** * Mouse-Button-Callback. * @param button Taste, die den Callback ausgeloest hat. * @param state Status der Taste, die den Callback ausgeloest hat. * @param x X-Position des Mauszeigers beim Ausloesen des Callbacks. * @param y Y-Position des Mauszeigers beim Ausloesen des Callbacks. */ static void cbMouseButton (int button, int state, int x, int y) { handleMouseEvent (x, y, mouseButton, button, state); } void mouseMovement(int x, int y) { if (getMouseEvent() == MOVE) setCameraMovement(x,y); if (getMouseEvent() == ZOOM) setCameraZoom(x,y); } /** * Callback fuer Aenderungen der Fenstergroesse. * Initiiert Anpassung der Projektionsmatrix an veraenderte Fenstergroesse. * @param w Fensterbreite (In). * @param h Fensterhoehe (In). */ static void cbReshape (int w, int h) { /* Das ganze Fenster ist GL-Anzeigebereich */ glViewport (0, 0, (GLsizei) w, (GLsizei) h); /* Anpassen der Projektionsmatrix an das Seitenverhaeltnis des Fensters */ setProjection ((GLdouble) w / (GLdouble) h); } /** * Registrierung der GLUT-Callback-Routinen. */ static void registerCallBacks (void) { /* Mouse-Button-Callback (wird ausgefuehrt, wenn eine Maustaste * gedrueckt oder losgelassen wird) */ glutMouseFunc (cbMouseButton); glutMotionFunc(mouseMovement); /* Timer-Callback - wird einmalig nach msescs Millisekunden ausgefuehrt */ glutTimerFunc (1000 / TIMER_CALLS_PS, /* msecs - bis Aufruf von func */ cbTimer, /* func - wird aufgerufen */ glutGet (GLUT_ELAPSED_TIME)); /* value - Parameter, mit dem func aufgerufen wird */ /* Reshape-Callback - wird ausgefuehrt, wenn neu gezeichnet wird (z.B. nach * Erzeugen oder Groessenaenderungen des Fensters) */ glutReshapeFunc (cbReshape); /* Display-Callback - wird an mehreren Stellen imlizit (z.B. im Anschluss an * Reshape-Callback) oder explizit (durch glutPostRedisplay) angestossen */ glutDisplayFunc (cbDisplay); /* Tasten-Druck-Callback - wird ausgefuehrt, wenn eine Taste gedrueckt wird */ glutKeyboardFunc (cbKeyboard); /* Spezialtasten-Druck-Callback - wird ausgefuehrt, wenn Spezialtaste * (F1 - F12, Links, Rechts, Oben, Unten, Bild-Auf, Bild-Ab, Pos1, Ende oder * Einfuegen) gedrueckt wird */ glutSpecialFunc (cbSpecial); /* Wird aufgerufen, wenn eine Taste wieder losgelassen wird! */ glutSpecialUpFunc(cbUpSpecial); /* Automat. Tastendruckwiederholung ignorieren */ glutIgnoreKeyRepeat (1); /* Wenn die Fenstergröße verändert wird. */ /*glutReshapeFunc(cgReshape);*/ } int readFile (char * name, char ** buffer) { FILE *f = fopen(name, "rb"); fseek(f, 0, SEEK_END); int pos = ftell(f); fseek(f, 0, SEEK_SET); (*buffer) = malloc(pos+1); fread(*buffer, pos-1, 1, f); (*buffer)[pos-1] = '\0'; fclose(f); } GLuint loadShaders(char * vertexShader, char * fragmentShader){ /* Create the shaders */ GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); /* Read Shader from File was here */ GLint Result = GL_FALSE; int InfoLogLength; /* Compile Vertex Shader */ printf("Compiling Vertex shader\n"); char * VertexSourcePointer = NULL; readFile(vertexShader, &VertexSourcePointer); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); glCompileShader(VertexShaderID); /* Check Vertex Shader */ glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); char * vertexShaderErrorMessage = calloc(InfoLogLength, sizeof(char)); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &(vertexShaderErrorMessage[0])); fprintf(stdout, "vertexShaderErrorMessage: %s\n", vertexShaderErrorMessage); /* Compile Fragment Shader */ printf("Compiling Fragment shader\n"); char * FragmentSourcePointer = NULL; readFile(fragmentShader, &FragmentSourcePointer); /*printf ("FragmentShader: \n\"%s\"\n", FragmentSourcePointer);*/ glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); glCompileShader(FragmentShaderID); /* Check Fragment Shader */ glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); char * fragmentShaderErrorMessage = calloc(InfoLogLength, sizeof(char)); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &(fragmentShaderErrorMessage[0])); fprintf(stdout, "fragmentShaderErrorMessage: %s\n", fragmentShaderErrorMessage); /* Link the program */ GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); /* Check the program */ glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); char * programErrorMessage = calloc(InfoLogLength, sizeof(char)); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &(programErrorMessage[0])); fprintf(stdout, "programErrorMessage: %s\n", programErrorMessage); glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); return ProgramID; } int loadTextureImage(Image * image, char * name, GLuint * tex) { if (!imageLoad(name, image)) { printf("Error reading image file"); exit(1); } glGenTextures(1, tex); glBindTexture(GL_TEXTURE_2D, *tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image->sizeX, image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data); } /** * Initialisiert das Programm (inkl. I/O und OpenGL) und startet die * Ereignisbehandlung. * @param title Beschriftung des Fensters * @param width Breite des Fensters * @param height Hoehe des Fensters * @return ID des erzeugten Fensters, 0 im Fehlerfall */ int initAndStartIO (char *title, int width, int height) { int windowID = 0; /* Kommandozeile immitieren */ int argc = 1; char *argv = "cmd"; G_Width = width; G_Height = height; /* Glut initialisieren */ glutInit (&argc, &argv); /* FensterInitialisierung */ glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); /* FensterGröße */ glutInitWindowSize (G_Width, G_Height); /* FensterPosition */ glutInitWindowPosition (0, 0); windowID = glutCreateWindow (title); if (windowID) { /* Hintergrund und so werden initialisiert (Farben) */ if (initScene ()) { G_ShaderID = loadShaders("waterVertexShader.vert", "waterFragmentShader.frag"); G_ShaderIDSimple = loadShaders("textureVertexShader.vert", "textureFragmentShader.frag"); G_ShaderIDSimpleD = loadShaders("textureVertexShader.vert", "textureDepthFragmentShader.frag"); G_ShaderColor = loadShaders("colorVertexShader.vert", "colorFragmentShader.frag"); registerCallBacks (); allocateMemoryStuffDepth(&G_TexCamera, &G_TexCameraDepth, &G_fboCam); allocateMemoryStuff(&G_TexReflection, &G_fboRefl); allocateMemoryStuff(&G_TexRefraction, &G_fboRefr); allocateMemoryStuffCube(&G_TexCube); G_sampler2dLoc = glGetUniformLocation(G_ShaderID, "texsampler"); G_samplerDepth2dLoc = glGetUniformLocation(G_ShaderID, "texsamplerDepth"); G_samplerCubeLoc = glGetUniformLocation(G_ShaderID, "texsamplerCube"); Image * imageSand, * imageGrass, * imageCaustics, * imageRocks, * imageSnow, * imageForest, * imageTundra; imageSand = malloc(sizeof(Image)); imageGrass = malloc(sizeof(Image)); imageCaustics = malloc(sizeof(Image)); imageRocks = malloc(sizeof(Image)); imageSnow = malloc(sizeof(Image)); imageForest = malloc(sizeof(Image)); imageTundra = malloc(sizeof(Image)); loadTextureImage(imageSand, "sand1.bmp", &G_TexImageSand ); loadTextureImage(imageGrass, "gras2.bmp", &G_TexImageGrass); loadTextureImage(imageCaustics, "caustics.bmp", &G_TexImageCaustics); loadTextureImage(imageRocks, "rocks.bmp", &G_TexImageRocks); loadTextureImage(imageSnow, "snow.bmp", &G_TexImageSnow); loadTextureImage(imageForest, "forest.bmp", &G_TexImageForest); loadTextureImage(imageTundra, "tundra.bmp", &G_TexImageTundra); glGenBuffers(1, &G_arrayBuffer); glBindBuffer(GL_ARRAY_BUFFER, G_arrayBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(G_data), G_data, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenBuffers (1, &G_cubeBuffer); glBindBuffer (GL_ARRAY_BUFFER, G_cubeBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(G_points), &G_points, GL_STATIC_DRAW); glBindBuffer (GL_ARRAY_BUFFER, 0); glGenBuffers (1, &G_SurfaceBuffer); glBindBuffer (GL_ARRAY_BUFFER, G_SurfaceBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(G_Surface), &G_Surface, GL_STATIC_DRAW); glBindBuffer (GL_ARRAY_BUFFER, 0); /* Wasser */ glGenBuffers (1, &G_WaterBuffer); glBindBuffer (GL_ARRAY_BUFFER, G_WaterBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getWaterList())*WORLD_SIZE*WORLD_SIZE, getWaterList(), GL_STREAM_DRAW); glBindBuffer (GL_ARRAY_BUFFER, 0); glGenBuffers (1, &G_WaterBufferIndex); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, G_WaterBufferIndex); glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof(*getWaterIndices())*WORLD_SIZE*WORLD_SIZE*3*2, getWaterIndices(), GL_STREAM_DRAW); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); /* Terrain */ glGenBuffers (1, &G_TerrainBuffer); glBindBuffer (GL_ARRAY_BUFFER, G_TerrainBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getTerrainList())*TERRAIN_SIZE*TERRAIN_SIZE, getTerrainList(), GL_STATIC_DRAW); glBindBuffer (GL_ARRAY_BUFFER, 0); glGenBuffers (1, &G_TerrainBufferIndex); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, G_TerrainBufferIndex); glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof(*getTerrainIndices())*TERRAIN_SIZE*TERRAIN_SIZE*3*2, getTerrainIndices(), GL_STATIC_DRAW); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); /* Caustics --> Indices des Terrains nutzen! */ glGenBuffers (1, &G_CausticsBuffer); glBindBuffer (GL_ARRAY_BUFFER, G_CausticsBuffer); glBufferData (GL_ARRAY_BUFFER, sizeof(*getTerrainCaustics())*TERRAIN_SIZE*TERRAIN_SIZE, getTerrainCaustics(), GL_STREAM_DRAW); glBindBuffer (GL_ARRAY_BUFFER, 0); glGenBuffers(1, &G_ObjectsBuffer); glBindBuffer(GL_ARRAY_BUFFER, G_ObjectsBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(G_Objects), G_Objects, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.0, 1.0, 1.0, 0.0); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderFBToCubeTexture(&G_TexCubeFront, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, -1); renderFBToCubeTexture(&G_TexCubeBack, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 1); renderFBToCubeTexture(&G_TexCubeBottom,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, -1, 0); renderFBToCubeTexture(&G_TexCubeTop, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 1, 0); renderFBToCubeTexture(&G_TexCubeLeft, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, -1, 0, 0); renderFBToCubeTexture(&G_TexCubeRight, GL_TEXTURE_CUBE_MAP_POSITIVE_X, 1, 0, 0); /* Die Endlosschleife wird angestoßen */ glutMainLoop (); windowID = 0; glDeleteFramebuffers(1, &G_fboCam); glDeleteTextures(1, &G_TexCamera); } else { glutDestroyWindow (windowID); windowID = 0; } } return windowID; } ================================================ FILE: src/io.h ================================================ #ifndef __IO_H__ #define __IO_H__ #define __DEBUG_GL_H__ /** * @file * CallBack-Funktionsköpfe * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #ifdef MACOSX #include #else #include #endif #include #include int initAndStartIO (char *title, int width, int height); #endif ================================================ FILE: src/logic.c ================================================ /** * @file * Hier ist die Datenhaltung und Programmlogik * * @author Tilman Nedele, Maurice Tollmien */ /* ---- System Header einbinden ---- */ #include #include #include #include #include #include #ifdef MACOSX #include #else #include #endif /* ---- Eigene Header einbinden ---- */ #include "logic.h" #include "vector.h" #include "scene.h" #include "types.h" #include "water.h" #include "terrain.h" /* Globale Variablen */ /** Licht an/aus */ InitType G_Light = ON; /** Hilfe an/aus */ InitType G_Help = OFF; /** Textur an/aus */ InitType G_Texture = ON; /** Mausbewegung zoom/move/none */ MouseInterpretType G_Mouse; /** Kameraposition */ CGVector3D G_CameraPosition = {CAMERA_X,CAMERA_Y,CAMERA_Z}; /** Position der Maus */ Movement G_MouseMove = {0.0,0.0,0.0}; /** Startpunkt der Mausbewegung */ CGVector3D G_LastMouseCenter = {0.0,0.0,0.0}; /** Anzahl der Quadrate für den Boden */ int G_QuadCount = 0; /** Welche Textur soll angezeigt werden */ int G_TextureCount = 5; /** Liste aller Kugeln */ Spheres * G_Spheres; int G_BallMoving = 0; Quads * G_Quads; /** Sollen sich die Kugeln bewegen? */ int G_SpheresMoving = 0; /** Ob die Partikel neu berechnet werden */ int G_ParticleFreeze = 0; /** Wie sollen die Partikel gezeichnet werden? */ ParticleType G_ParticleType = line; /** Schatten zeichnen? */ int G_DrawShadows = 0; /** Partikel hinzufügen? */ int G_UpDownKeys[2] = {0,0}; /** Kamer auf einem Partikel? */ int G_ParticleCamera = 0; /** Position des Partikel in der Liste mit der Kamera */ int G_CameraParticlePos = 0; /** Verfolgermodus? */ int G_PersecutorParticle = 0; /** UP-Vektor anzeigen? */ int G_ShowUpVector = 0; /** FPS */ int G_FPS = 0; /** FPS counter */ double G_Counter = 0.0-EPS; /* ------- GETTER / SETTER ------- */ int getFPS(void) { return G_FPS; } /** * Setzt die Ansicht des Up-Vektors */ void toggleShowUpVector (void) { G_ShowUpVector = !G_ShowUpVector; } /** * Getter für Ansicht des Up-Vektors * @return 0 / 1 */ int getShowUpVector (void) { return G_ShowUpVector; } /** * Getter für die Position des Partikel mit der Kamera */ int getCameraParticlePos() { return G_CameraParticlePos; } /** * Ändert den Verfolger-Modus */ void togglePersecutorParticle (void) { G_PersecutorParticle = !G_PersecutorParticle; } /** * Ändert den Kameramodus. */ void toggleParticleCamera (void) { G_ParticleCamera = !G_ParticleCamera; } /** * Ob der Verfolgermodus gesetzt ist */ int getParticleCamera (void) { return G_ParticleCamera; } void startMovingBall(void) { G_BallMoving = G_BallMoving == 0 ? 1 : 0; } /** * Setzt, ob ein Up/Down-Key gedrückt ist. * key == 0 = down * key == 1 = up * value = gesetzt/nicht gesetzt. */ void setKey (int key, int value) { if (key < 2) G_UpDownKeys[key] = value; } /** * Ob Schatten gezeichnet werden sollen, oder nicht. */ void toggleShadows(void) { G_DrawShadows = !G_DrawShadows; } /** * Ob Schatten gezeichnet werden sollen, oder nicht. */ int getDrawShadows(void) { return G_DrawShadows; } /** * Ändert den Typ der Partikel */ void toggleParticleType (void) { if (G_ParticleType + 1 > sphere) G_ParticleType = 0; else G_ParticleType++; } /** * Welcher Typ die Partikel sind */ ParticleType getParticleType (void) { return G_ParticleType; } /** * Ob die Partikel sich bewegen oder nicht. */ void toggleParticleFreeze (void) { G_ParticleFreeze = !G_ParticleFreeze; if (G_SpheresMoving) G_SpheresMoving = 0; } /** * Gibt eine Sphere zurück. */ Spheres * getSphereList (void) { return G_Spheres; } /** * Gibt eine Sphere zurück. */ Quads * getQuadList (void) { return G_Quads; } /** * Ändert den Wert des Boolean, ob sich die Kugeln bewegen dürfen. */ void toggleSpheresMoving (void) { G_SpheresMoving = !G_SpheresMoving; } /** * Get-Function für den Status des Lichts * @return Status des Lichts */ InitType getLightStatus() { return G_Light; } /** * Set-Function für den Status des Lichts * @param Status des Lichts */ void setLightStatus(InitType state) { G_Light = state; } void toggleLight (void) { G_Light = !G_Light; } /** * Get-Function für den Status der Hilfe * @return Status der Hilfe */ InitType getHelpStatus() { return G_Help; } /** * Set-Function für den Status der Hilfe * @param Status der Hilfe */ void setHelpStatus(InitType state) { G_Help = state; } /** * Get-Function für den Status der Texturen * @return Status der Texturen */ InitType getTextureStatus() { return G_Texture; } /** * Set-Function für den Status der Textur * @param Status der Textur */ void setTextureStatus(InitType state) { G_Texture = state; } /** * Set-Function für den Status der Maus * @param Status der Maus */ void setMouseEvent(MouseInterpretType state,int x, int y) { G_MouseMove[0] = 0.0; G_MouseMove[2] = 0.0; G_LastMouseCenter[0] = x; G_LastMouseCenter[2] = y; G_Mouse = state; } /** * Get-Function für den Status der Maus * @return Status der Maus */ MouseInterpretType getMouseEvent() { return G_Mouse; } /** * Gibt die Kamerakoordinate zurück. */ double getCameraPosition (int axis) { if (axis >= 0 && axis < 3) return G_CameraPosition[axis]; return 0.0; } /** * Erhöht die Größe der Unterteilungen um den Faktor 2 */ void incQuadCount() { if (G_QuadCount < 9) ++G_QuadCount; } /** * Verkleinert die Größe der Unterteilungen um den Divisor 2 */ void decQuadCount() { if (G_QuadCount > 0) --G_QuadCount; } /** * Rekursionstiefe für die Bodenfläche */ int getQuadCount() { return G_QuadCount; } /** * Bewegt die Kamera auf einem Kugelradius um den Szenenmittelpunkt. */ void setCameraMovement(int x,int y) { CGVector3D tmp; double factor, radius = vectorLength3D(G_CameraPosition); tmp[0] = G_CameraPosition[0]; tmp[1] = G_CameraPosition[1]; tmp[2] = G_CameraPosition[2]; G_MouseMove[0] = x-G_LastMouseCenter[0]; G_MouseMove[2] = y-G_LastMouseCenter[2]; G_LastMouseCenter[0] = x; G_LastMouseCenter[2] = y; /* Bewegung um Y-Achse: */ G_CameraPosition[0] = cos(-G_MouseMove[0]*PI/180.0/CAMERA_MOVEMENT_SPEED)*tmp[0] + sin(-G_MouseMove[0]*PI/180.0/CAMERA_MOVEMENT_SPEED)*tmp[2]; G_CameraPosition[2] = -sin(-G_MouseMove[0]*PI/180.0/CAMERA_MOVEMENT_SPEED)*tmp[0] + cos(-G_MouseMove[0]*PI/180.0/CAMERA_MOVEMENT_SPEED)*tmp[2]; /* Bewegung oben/unten */ G_CameraPosition[1] += G_MouseMove[2]/(CAMERA_MOVEMENT_SPEED/2)*(vectorLength3D(G_CameraPosition)/100.0); factor = 1.0 / (vectorLength3D(G_CameraPosition) / radius); multiplyVectorScalar (G_CameraPosition, factor, &G_CameraPosition); } /** * Verlängert/verkürzt den Vektor zur Kamera. */ void setCameraZoom(int x,int y) { double factor = 1.0 + (CAMERA_ZOOM_SPEED / 1000.0) * ((G_MouseMove[2] < 0.0) ? -1.0 : 1.0); G_MouseMove[0] = x-G_LastMouseCenter[0]; G_MouseMove[2] = y-G_LastMouseCenter[2]; G_LastMouseCenter[0] = x; G_LastMouseCenter[2] = y; G_CameraPosition[0] *= factor; G_CameraPosition[1] *= factor; G_CameraPosition[2] *= factor; } /* ------- BERECHNUNGEN ------- */ /** * Berechnet die Bewegung der Kugeln * @param interval - Zeit */ void moveSpheres (double interval) { int i; for (i=0;ipos[0] += SPHERE_MOVE_SPEED*interval; s->pos[1] += 0.0; s->pos[2] += 0.0; } } /** * Berechnet alle Funktionen, die vom interval abhängig sind * @param interval - Zeit */ void calcTimeRelatedStuff (double interval) { moveSpheres(interval); if (!G_ParticleFreeze) { calcWaterAttributes(interval); } /* Keine Partikel hinzufügen oder löschen! */ /* if (G_UpDownKeys[0]) { for (i=0;i<100;i++) { deleteParticle (); } } else if (G_UpDownKeys[1]) { for (i=0;i<100;i++) { addParticle (); } } */ G_Counter += interval; if (G_Counter >= 1.0) G_Counter = 0.0 -EPS; if (G_Counter <= 0.0) G_FPS = (int) 1.0/interval; } /** * Berechnet anhand der Rekursionstiefe die Anzahl der Quadrate auf dem Boden * @param p1,p2,p3,p4 - Die Ecken des Quadrats * @param rek - Rekursionstiefe * @param color - die Farbe der Quadrate * */ void drawRecursiveQuad(CGPoint3f p1, CGPoint3f p2, CGPoint3f p3, CGPoint3f p4, int rek, int color) { CGPoint3f middle0 = {0.0,0.0,0.0}, middle1 = {0.0,0.0,0.0}, middle2 = {0.0,0.0,0.0}, middle3 = {0.0,0.0,0.0}, center = {0.0,0.0,0.0}; center[0] = (p1[0] + p3[0]) / 2; center[2] = (p1[2] + p3[2]) / 2; middle0[0] = (p1[0] + p2[0]) / 2; middle0[2] = (p1[2] + p2[2]) / 2; middle1[0] = (p2[0] + p3[0]) / 2; middle1[2] = (p2[2] + p3[2]) / 2; middle2[0] = (p3[0] + p4[0]) / 2; middle2[2] = (p3[2] + p4[2]) / 2; middle3[0] = (p4[0] + p1[0]) / 2; middle3[2] = (p4[2] + p1[2]) / 2; if (rek > 0) { drawRecursiveQuad(center,middle0,p2,middle1, rek-1, color); drawRecursiveQuad(center,middle1,p3,middle2, rek-1, !color); drawRecursiveQuad(center,middle2,p4,middle3, rek-1, color); drawRecursiveQuad(center,middle3,p1,middle0, rek-1, !color); } else { drawVertex(p4,p3,p2,p1, color); } } /* ------- INIT ------- */ /** * Initialisiert die Kamera. */ void initCameraPosition () { G_CameraPosition[0] = CAMERA_X; G_CameraPosition[1] = CAMERA_Y; G_CameraPosition[2] = CAMERA_Z; } /** * Initialisiert die Kugeln. */ void initSpheres(void) { int i; G_Spheres = malloc (sizeof(*G_Spheres) * SPHERE_CNT); for (i=0;iinterpolatedPoints = NULL; sphere->interpolatedPointsAll = NULL; sphere->controlPoints = NULL; sphere->t = 0.0; sphere->pos[0] = rand() % (int)WORLD_SIZE/2 - rand() % (int)WORLD_SIZE/2+150; sphere->pos[1] = GROUND_HEIGHT-WORLD_SIZE/2.0+0.1 + SPHERE_R + 10; sphere->pos[2] = rand() % (int)WORLD_SIZE/2 - rand() % (int)WORLD_SIZE/2; sphere->newPos[0] = 0.0; sphere->newPos[1] = 0.0; sphere->newPos[2] = 0.0; sphere->color[0] = rand()%255; sphere->color[1] = rand()%255; sphere->color[2] = rand()%255; G_Spheres[i] = sphere; } } /** * Initialisiert die Quads. */ void initQuads(void) { int i; G_Quads = malloc (sizeof(*G_Quads) * QUAD_CNT); for (i=0;ipos[0] = -40; quads->pos[1] = GROUND_HEIGHT-WORLD_SIZE/2.0+0.1+QUAD_SIDE/2 ; quads->pos[2] = -40; G_Quads[i] = quads; } } /** * Hier findet die komplette Initialisierung des kompletten SPIEeles statt. * Inklusive der Datenhaltung und des SPIEelfeldes. */ void initGame () { initCameraPosition(); initTerrain(); initWater(); calcFixWaterPoints(getTerrainList()); /*setRandomize();*/ } ================================================ FILE: src/logic.h ================================================ #ifndef __LOGIC_H__ #define __LOGIC_H__ #define __DEBUG_GL_H__ /** * @file * Programmlogik und Datenhaltung * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" /* eig. Funktionen */ /* ------- GETTER / SETTER ------- */ InitType getLightStatus(void); void setLightStatus(InitType state); InitType getHelpStatus(void); void setHelpStatus(InitType state); InitType getTextureStatus(void); void setTextureStatus(InitType state); void setMouseEvent(MouseInterpretType state,int x, int y); MouseInterpretType getMouseEvent(void); double getCameraPosition (int axis); int getTextureSize(void); void setCameraMovement(int x,int y); void setCameraZoom(int x,int y); void toggleLight (void); Spheres * getSphereList (void); void incQuadCount(); void decQuadCount(); int getQuadCount(); void toggleSpheresMoving (void); int getTextureCount(); void nextTexture(); Particle * getParticleList (void); int getParticleCnt (void); void toggleParticleFreeze (void); void toggleParticleType (void); ParticleType getParticleType (void); void toggleShadows(void); int getDrawShadows(void); void setKey (int key, int value); void toggleParticleCamera (void); void togglePersecutorParticle (void); int getParticleCamera (void); void nextCameraParticle(); int getCameraParticlePos(); Particle getCameraParticle (void); int getShowUpVector (void); void toggleShowUpVector (void); int getFPS(void); void startMovingBall(void); Quads * getQuadList (void); /* ------- BERECHNUNGEN ------- */ void moveCamera(int x, int y); void zoomCamera(int x, int y); void calcTimeRelatedStuff (double interval); void drawRecursiveQuad(CGPoint3f p1, CGPoint3f p2, CGPoint3f p3, CGPoint3f p4, int rek, int color); /* ------- INIT ------- */ void initGame (); #endif ================================================ FILE: src/main.c ================================================ /** * @file * ein erster Versuch, eine eigene Datei zu erstellen... * @author Maurice Tollmien. */ /* ---- System Header einbinden ---- */ #include #include #include #include #include #ifdef MACOSX #include #else #include #endif #ifdef WIN32 #include #endif /* ---- Eigene Header einbinden ---- */ #include "io.h" #include "scene.h" #include "types.h" /** * Hauptprogramm. * Initialisiert Fenster, Anwendung und Callbacks, startet glutMainLoop. * @param argc Anzahl der Kommandozeilenparameter (In). * @param argv Kommandozeilenparameter (In). * @return Rueckgabewert im Fehlerfall ungleich Null. */ int main (int argc, char **argv) { srand (time (0)); if (!initAndStartIO ("nen Programm", 1080, 1080)) { fprintf (stderr, "Initialisierung fehlgeschlagen!\n"); return 1; } return 0; } ================================================ FILE: src/particle.c ================================================ /** * @file * Hier ist die Datenhaltung und Programmlogik * * @author Tilman Nedele, Maurice Tollmien */ /* ---- System Header einbinden ---- */ #include #include #include #include #include #ifdef MACOSX #include #else #include #endif /* ---- Eigene Header einbinden ---- */ #include "particle.h" #include "logic.h" #include "vector.h" #include "types.h" /** Globale Variablen */ /** Liste mit Partikeln */ Particle * G_Particles; /** Anzahl der Partikel */ int G_ParticleCnt = PARTICLE_CNT; /** Init-Wert der Länge der Feder ohne Dehnung */ double G_StructureSpringLengthInit; double G_SheerSpringLengthInit; double G_BendingSpringLengthInit; /** * Gibt die Liste mit Partikeln zurück */ Particle * getParticleList (void) { return G_Particles; } /** * Getter für ein Partikel an der Position i * @return das Partikel */ Particle getParticleAt(int i) { return G_Particles[i]; } /** * Gibt die Anzahl der Partikel zurück. */ int getParticleCnt (void) { return G_ParticleCnt; } /** * Setzt die Partikelanzahl */ void setParticleCnt (int i) { G_ParticleCnt = i; } void calcSpringForce (Particle p1, Particle p2, double initLength, double k, CGVector3D * res) { CGVector3D tmp = {0.0,0.0,0.0}; double len = 0.0; /* Tatsächlicher Abstand beider Punkte */ subtractVectorVector (p1->s, p2->s, &tmp); /* Länge des Abstandes */ len = vectorLength3D (tmp); /* Bildung des Einheitsvektors in die Richtung der Kraft */ divideVectorScalar (tmp, len, &tmp); /* Abweichung der Initialen Länge berechnen */ len = len - initLength; if (abs(len) < EPS_LEN) len = 0.0; /* Abweichung mit Federkonstante multiplizieren */ multiplyVectorScalar (tmp, len * -k, &tmp); if (vectorLength3D(tmp) <= EPS_F) multiplyVectorScalar (tmp, 0, &tmp); /* NEU! */ if (vectorLength3D(tmp) > MAX_F) { multiplyVectorScalar (tmp, 0.0001, &tmp); } multiplyVectorScalar (tmp, -1, &tmp); (*res)[0] = tmp[0]; (*res)[1] = tmp[1]; (*res)[2] = tmp[2]; } void correctConcreteParticleSymmetric (Particle p, Particle p2, double initValue) { CGVector3D tmp = {0.0,0.0,0.0}; double len, tooMuch; double moveLen; subtractVectorVector (p->s, p2->s, &tmp); len = vectorLength3D (tmp); tooMuch = 1.0 - (len / initValue); /* Grenze überschritten! Feder zu lang oder kurz! */ if ((double)(abs(tooMuch * 1000.0)/1000.0) > SPRING_EXPANSION_MAX) { if (len > initValue) { moveLen = initValue * SPRING_EXPANSION_MAX + initValue; } else { moveLen = -initValue * SPRING_EXPANSION_MAX + initValue; } /* Wenn der Vektor verkürzt werden soll, ist das Ergebnis positiv! */ moveLen = (len - moveLen) / 2.0; /* normierter Richtungsvektor in Richtung des Partikels p */ divideVectorScalar (tmp, len, &tmp); /* Vektor zeigt Richtung Partikel p, wenn er verkürzt werden soll! */ multiplyVectorScalar (tmp, moveLen, &tmp); addVectorVector (p2->s, tmp, &(p2->s)); multiplyVectorScalar (tmp, -1, &tmp); addVectorVector (p->s, tmp, &p->s); } } void correctConcreteParticleP2 (Particle p, Particle p2, double initValue) { CGVector3D tmp = {0.0,0.0,0.0}; double len, tooMuch; double moveLen; subtractVectorVector (p->s, p2->s, &tmp); len = vectorLength3D (tmp); tooMuch = 1.0 - (len / initValue); /* Grenze überschritten! Feder zu lang oder kurz! */ if ((double)(abs(tooMuch * 1000.0)/1000.0) > SPRING_EXPANSION_MAX) { if (len > initValue) { moveLen = initValue * SPRING_EXPANSION_MAX + initValue; } else { moveLen = -initValue * SPRING_EXPANSION_MAX + initValue; } /* Wenn der Vektor verkürzt werden soll, ist das Ergebnis positiv! */ moveLen = len - moveLen; /* normierter Richtungsvektor in Richtung des Partikels p */ divideVectorScalar (tmp, len, &tmp); /* Vektor zeigt Richtung Partikel p, wenn er verkürzt werden soll! */ multiplyVectorScalar (tmp, moveLen, &tmp); addVectorVector (p2->s, tmp, &(p2->s)); } } void correctSpringLengthPosition(Particle p, int i, int j) { int sqrtLen = (int)(sqrt(G_ParticleCnt)+0.5); /** ================== STRUKTURFEDERN ===================== */ if (1) { /* Untere Feder */ if (i > 0) { /*Particle p2 = G_Particles[(i-1)*sqrtLen+j]; correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit);*/ } /* Obere Feder */ if (i < sqrtLen-1) { Particle p2 = G_Particles[(i+1)*sqrtLen+j]; if ((i == sqrtLen-2 && j == sqrtLen-1) || (i == sqrtLen-2 && j == 0)) { correctConcreteParticleP2(p2, p, G_StructureSpringLengthInit); } else { correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit); } } /* Rechte Feder */ if (j < sqrtLen-1) { Particle p2 = G_Particles[i*sqrtLen+(j+1)]; correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit); /*if (i == sqrtLen-1 && j == sqrtLen-2) { correctConcreteParticleP2(p2, p, G_StructureSpringLengthInit); } else { correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit); }*/ } /* Linke Feder */ if (j > 0) { Particle p2 = G_Particles[i*sqrtLen+(j-1)]; correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit); /*if (i == sqrtLen-1 && j == 1) { correctConcreteParticleP2(p2, p, G_StructureSpringLengthInit); } else { correctConcreteParticleSymmetric (p, p2, G_StructureSpringLengthInit); }*/ } } /** ==================== SCHERFEDERN ====================== */ if (1) { /* Links oben */ if (i < sqrtLen-1 && j > 0) { Particle p2 = G_Particles[(i+1)*sqrtLen+(j-1)]; if (i == sqrtLen-2 && j == 1) { correctConcreteParticleP2(p2, p, G_SheerSpringLengthInit); } else { correctConcreteParticleSymmetric (p, p2, G_SheerSpringLengthInit); } } /* Rechts oben */ if (i < sqrtLen-1 && j < sqrtLen-1) { Particle p2 = G_Particles[(i+1)*sqrtLen+(j+1)]; if (i == sqrtLen-2 && j == sqrtLen-2) { correctConcreteParticleP2(p2, p, G_SheerSpringLengthInit); } else { correctConcreteParticleSymmetric (p, p2, G_SheerSpringLengthInit); } } if (i > 0 && j > 0) { Particle p2 = G_Particles[(i-1)*sqrtLen+(j-1)]; correctConcreteParticleSymmetric (p, p2, G_SheerSpringLengthInit); } if (i > 0 && j < sqrtLen-1) { Particle p2 = G_Particles[(i-1)*sqrtLen+(j+1)]; correctConcreteParticleSymmetric (p, p2, G_SheerSpringLengthInit); } } } double calcWindForce (CGVector3D va, CGVector3D vb, CGVector3D vc, CGVector3D wind) { CGVector3D a = {0.0,0.0,0.0}; CGVector3D b = {0.0,0.0,0.0}; CGVector3D c = {0.0,0.0,0.0}; CGVector3D norm = {0.0,0.0,0.0}; double la, lb, lc, s, f; subtractVectorVector (vb, va, &a); subtractVectorVector (vc, vb, &b); subtractVectorVector (va, vc, &c); la = vectorLength3D (a); lb = vectorLength3D (b); lc = vectorLength3D (c); s = (la + lb + lc ) / 2.0; f = sqrt (s * (s-la) * (s-lb) * (s-lc)); crossProduct3D (norm, a, b); return scalarProduct (norm, wind) * f * WIND_FORCE; } /** * Berechnet mitHilfe von Euler die neuen Attribute der Partikel * * @param spheres - Liste aller Kugeln * @param sphereCnt - Anzahl aller Kugeln * @param interval - Zeit * @param persecutorParticleMode - Verfolgermodus */ void calcParticleAttributesEuler (Spheres * spheres, int sphereCnt, double interval,int persecutorParticleMode, int cameraParticlePos) { int i,j,k; int sqrtLen = (int)(sqrt(G_ParticleCnt)+0.5); for (i=0;i= sqrtLen-2 /* || (i == sqrtLen-1 && j == sqrtLen-1) || (i == sqrtLen-1 && j == 0) */ )) { /** ================== STRUKTURFEDERN ===================== */ /* Linke Feder */ if (i > 0) { calcSpringForce (G_Particles[(i-1)*sqrtLen+j], p, G_StructureSpringLengthInit, K_STRUCTURE, &tmp); addVectorVector (fInt, tmp, &fInt); divideVectorScalar (G_Particles[(i-1)*sqrtLen+j]->f, 5, &tmp); addVectorVector (fIntNeighbours, tmp, &fIntNeighbours); } /* Rechte Feder */ if (i < sqrtLen-1) { calcSpringForce (G_Particles[(i+1)*sqrtLen+j], p, G_StructureSpringLengthInit, K_STRUCTURE, &tmp); addVectorVector (fInt, tmp, &fInt); divideVectorScalar (G_Particles[(i+1)*sqrtLen+j]->f, 5, &tmp); addVectorVector (fIntNeighbours, tmp, &fIntNeighbours); } /* Untere Feder */ if (j > 0) { calcSpringForce (G_Particles[i*sqrtLen+(j-1)], p, G_StructureSpringLengthInit, K_STRUCTURE, &tmp); addVectorVector (fInt, tmp, &fInt); divideVectorScalar (G_Particles[i*sqrtLen+(j-1)]->f, 5, &tmp); addVectorVector (fIntNeighbours, tmp, &fIntNeighbours); } /* Obere Feder */ if (j < sqrtLen-1) { calcSpringForce (G_Particles[i*sqrtLen+(j+1)], p, G_StructureSpringLengthInit, K_STRUCTURE, &tmp); addVectorVector (fInt, tmp, &fInt); divideVectorScalar (G_Particles[i*sqrtLen+(j+1)]->f, 5, &tmp); addVectorVector (fIntNeighbours, tmp, &fIntNeighbours); } /** ==================== SCHERFEDERN ====================== */ /* Links unten */ if (i > 0 && j > 0) { calcSpringForce (G_Particles[(i-1)*sqrtLen+(j-1)], p, G_SheerSpringLengthInit, K_SHEER, &tmp); addVectorVector (fInt, tmp, &fInt); } if (i > 0 && j < sqrtLen-1) { calcSpringForce (G_Particles[(i-1)*sqrtLen+(j+1)], p, G_SheerSpringLengthInit, K_SHEER, &tmp); addVectorVector (fInt, tmp, &fInt); } if (i < sqrtLen-1 && j > 0) { calcSpringForce (G_Particles[(i+1)*sqrtLen+(j-1)], p, G_SheerSpringLengthInit, K_SHEER, &tmp); addVectorVector (fInt, tmp, &fInt); } if (i < sqrtLen-1 && j < sqrtLen-1) { calcSpringForce (G_Particles[(i+1)*sqrtLen+(j+1)], p, G_SheerSpringLengthInit, K_SHEER, &tmp); addVectorVector (fInt, tmp, &fInt); } /** ================== BEUGUNGSFEDERN ===================== */ if (i > 1) { calcSpringForce (G_Particles[(i-2)*sqrtLen+j], p, G_BendingSpringLengthInit, K_BEND, &tmp); addVectorVector (fInt, tmp, &fInt); } if (i < sqrtLen-2) { calcSpringForce (G_Particles[(i+2)*sqrtLen+j], p, G_BendingSpringLengthInit, K_BEND, &tmp); addVectorVector (fInt, tmp, &fInt); } if (j > 1) { calcSpringForce (G_Particles[i*sqrtLen+(j-2)], p, G_BendingSpringLengthInit, K_BEND, &tmp); addVectorVector (fInt, tmp, &fInt); } if (j < sqrtLen-2) { calcSpringForce (G_Particles[i*sqrtLen+(j+2)], p, G_BendingSpringLengthInit, K_BEND, &tmp); addVectorVector (fInt, tmp, &fInt); } /*divideVectorScalar (fInt, 5, &fInt); addVectorVector (fInt, fIntNeighbours, &fInt);*/ if (vectorLength3D(fInt) <= F_MIN) { multiplyVectorScalar (fInt, 0, &fInt); } p->f[0] = fInt[0]; p->f[1] = fInt[1]; p->f[2] = fInt[2]; /* Kollision mit Wind :-) */ if (i == 0 || i == sqrtLen-1) { factor *= WIND_EDGE_FACTOR; } if (j == 0 || j == sqrtLen-1) { factor *= WIND_EDGE_FACTOR; } if (i > 0) { if (j > 0) { /* 8 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i)*sqrtLen+(j-1)]->s, G_Particles[(i-1)*sqrtLen+(j-1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); /* 1 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i-1)*sqrtLen+(j-1)]->s, G_Particles[(i-1)*sqrtLen+(j)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); } if (j < sqrtLen-1) { /* 2 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i-1)*sqrtLen+(j)]->s, G_Particles[(i-1)*sqrtLen+(j+1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); /* 3 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i-1)*sqrtLen+(j+1)]->s, G_Particles[(i)*sqrtLen+(j+1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); } } if (i < sqrtLen-1) { if (j < sqrtLen-1) { /* 4 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i)*sqrtLen+(j+1)]->s, G_Particles[(i+1)*sqrtLen+(j+1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); /* 5 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i+1)*sqrtLen+(j+1)]->s, G_Particles[(i+1)*sqrtLen+(j)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); } if (j > 0) { /* 6 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i+1)*sqrtLen+(j)]->s, G_Particles[(i+1)*sqrtLen+(j-1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); /* 7 */ multiplyVectorScalar (wind, calcWindForce(G_Particles[(i)*sqrtLen+(j)]->s, G_Particles[(i+1)*sqrtLen+(j-1)]->s, G_Particles[(i)*sqrtLen+(j-1)]->s, wind), &tmp2); addVectorVector (fWindForce, tmp2, &fWindForce); } } multiplyVectorScalar (fWindForce, factor, &fWindForce); /* Kräfte */ addVectorVector (fInt, fExt, &fComplete); addVectorVector (fComplete, fWindForce, &fComplete); /* Beschleunigung */ p->a[0] = (-LAMDA * p->v[0] + fComplete[0]) / p->m; p->a[1] = (-LAMDA * p->v[1] + fComplete[1]) / p->m; p->a[2] = (-LAMDA * p->v[2] + fComplete[2]) / p->m; /* Geschwindigkeit */ multiplyVectorScalar (p->a, interval, &tmp); addVectorVector (p->v, tmp, &p->v); if (vectorLength3D(p->v) > MAX_V) { /*printf ("V = %f\n", vectorLength3D(p->v));*/ divideVectorScalar (p->v, vectorLength3D(p->v), &(p->v)); multiplyVectorScalar(p->v, MAX_V, &(p->v)); } /* Ort */ multiplyVectorScalar (p->v, interval, &tmp); addVectorVector (p->s, tmp, &p->s); /* Up */ crossProduct3D (tmp, p->v, p->a); crossProduct3D (tmp, tmp, p->v); if (vectorLength3D(tmp) > 0.1) { p->up[0] = tmp[0]; p->up[1] = tmp[1]; p->up[2] = tmp[2]; } /* Eventuelle Anpassung der Entfernung zwischen Partikeln, wenn die Feder zu lang oder zu klein wird! */ correctSpringLengthPosition(p, i, j); /* Kollision mit Boden */ if (p->s[1] <= -WORLD_SIZE/2.0 + 0.5) { p->s[1] = -WORLD_SIZE/2.0 + 0.5; multiplyVectorScalar(p->v, 0, &(p->v)); } /* Kollision mit Kugel(n) */ for (k=0;ks, s->pos, &tmp); dist = vectorLength3D(tmp); if (dist < SPHERE_R+4.5) { divideVectorScalar(tmp, dist, &tmp); multiplyVectorScalar(tmp, SPHERE_R-dist+4.5, &tmp); addVectorVector(p->s, tmp, &(p->s)); p->v[0] = 0; p->v[1] = 0; p->v[2] = 0; } } /* Kollision mit Quad(s) */ for (k=0;ks[1] <= s->pos[1]+QUAD_SIDE/2+2.5 && p->s[0] <= s->pos[0]+QUAD_SIDE/2+2.5 && p->s[0] >= s->pos[0]-QUAD_SIDE/2-2.5 && p->s[2] <= s->pos[2]+QUAD_SIDE/2+2.5 && p->s[2] >= s->pos[2]-QUAD_SIDE/2-2.5 ) { p->s[1] = s->pos[1]+QUAD_SIDE/2+2.5; multiplyVectorScalar(p->v, 0, &(p->v)); } } } else { Particle p2 = G_Particles[(i-1)*sqrtLen+j]; correctConcreteParticleP2(p, p2, G_StructureSpringLengthInit); } } } } /** * Fügt ein Partikel der Liste hinzu. */ void addParticle (void) { Particle p = malloc (sizeof(**G_Particles)); G_Particles = realloc (G_Particles, sizeof(*G_Particles) * ++G_ParticleCnt); p->s[0] = rand()%(int)(5*WORLD_SIZE)/20.0 - rand()%(int)(5*WORLD_SIZE)/20.0; p->s[1] = rand()%(int)(5*WORLD_SIZE)/20.0 - rand()%(int)(5*WORLD_SIZE)/20.0; p->s[2] = rand()%(int)(5*WORLD_SIZE)/20.0 - rand()%(int)(5*WORLD_SIZE)/20.0; p->v[0] = 0.1; p->v[1] = 0.0; p->v[2] = 0.0; p->a[0] = 0.0; p->a[1] = 0.0; p->a[2] = 0.0; p->up[0] = 0.0; p->up[1] = 0.0; p->up[2] = 0.0; G_Particles[G_ParticleCnt-1] = p; } /** * Löscht das letzte Partikel */ void deleteParticle (void) { if (G_ParticleCnt >= 1) { free(G_Particles[G_ParticleCnt-1]); G_Particles = realloc (G_Particles, sizeof(*G_Particles) * --G_ParticleCnt); } } /** * Initialisiert die Partikel. */ void initParticles(void) { int i,j; G_Particles = malloc (sizeof(*G_Particles) * G_ParticleCnt * G_ParticleCnt); for (i=0;i<(int)(sqrt(G_ParticleCnt)+0.5);i++) { for (j=0;j<(int)(sqrt(G_ParticleCnt)+0.5);j++) { Particle p = malloc (sizeof(**G_Particles)); p->s[0] = PARTICLE_HEIGHT_INIT ; p->s[1] = i/((sqrt(G_ParticleCnt)))*WORLD_SIZE - WORLD_SIZE/2+0; p->s[2] = j/((sqrt(G_ParticleCnt)))*WORLD_SIZE - WORLD_SIZE/2; /*p->s[0] = i/((sqrt(G_ParticleCnt)))*WORLD_SIZE - WORLD_SIZE/2; p->s[1] = PARTICLE_HEIGHT_INIT; p->s[2] = j/((sqrt(G_ParticleCnt)))*WORLD_SIZE - WORLD_SIZE/2;*/ p->v[0] = 0.0; p->v[1] = 0.0; p->v[2] = 0.0; p->a[0] = 0.0; p->a[1] = 0.0; p->a[2] = 0.0; p->up[0] = 0.0; p->up[1] = 0.0; p->up[2] = 0.0; p->m = PARTICLE_M; p->f[0] = 0.0; p->f[1] = 0.0; p->f[2] = 0.0; G_Particles[i*(int)(sqrt(G_ParticleCnt)+0.5) +j] = p; } } G_StructureSpringLengthInit = abs((i+1)/((sqrt(G_ParticleCnt)))*WORLD_SIZE - i/((sqrt(G_ParticleCnt)))*WORLD_SIZE); G_SheerSpringLengthInit = sqrt(pow(G_StructureSpringLengthInit, 2) + pow(G_StructureSpringLengthInit, 2)); G_BendingSpringLengthInit = 2 * G_StructureSpringLengthInit; printf ("Strukturfeder-Länge: %f, Scherfeder-Länge: %f, Beugungsfeder-Länge: %f\n", G_StructureSpringLengthInit, G_SheerSpringLengthInit, G_BendingSpringLengthInit); } ================================================ FILE: src/particle.h ================================================ #ifndef __PARTICLE_H__ #define __PARTICLE_H__ #define __DEBUG_GL_H__ /** * @file * Programmlogik und Datenhaltung * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" #define PARTICLE_HEIGHT_INIT 40 #define PARTICLE_CNT 0 #define PARTICLE_LEN 1.0 #define PARTICLE_M 1.0 #define K_WEAK 1.0 #define K_WEAK_INTERPOL 0.05 #define K_V 1.5 #define GAUSS 10000.0 #define CAMERA_PARTICLE_MULT 2.5 Particle * getParticleList (void); int getParticleCnt (void); void initParticles(void); void calcParticleAttributesEuler (Spheres * spheres, int sphereCnt, double interval,int persecutorParticleMode, int cameraParticlePos); void addParticle (void); void deleteParticle (void); Particle getParticleAt(int i); #endif ================================================ FILE: src/scene.c ================================================ /** * @file * Hier wird vll gezeichnet... * * @author Maurice Tollmien, Tilman Nedele */ /* ---- System Header einbinden ---- */ #include #include #include #include #include #include #include #ifdef MACOSX #include #else #include #endif #include /* ---- Eigene Header einbinden ---- */ #include "scene.h" #include "logic.h" #include "types.h" #include "water.h" #include "terrain.h" #include "vector.h" /* ---- Globale Variablen für die Farben der Wände ------ */ float G_R; float G_G; float G_B; float G_Alpha; float G_Shininess; int G_Emission; /* ---- Funktionen ---- */ /** * Wird aufgerufen, wenn "h" gedrückt worden ist. * Gibt einen Text auf einem schwarzen Hintergrund auf dem Bildschirm aus */ void printHelp (void) { /* Textfarbe */ GLfloat textColor[3] = { 1.0f, 0.5f, 0.5f }; drawString (0.2f, 0.1f, textColor, HELP_OUTPUT_1); drawString (0.2f, 0.125f, textColor, HELP_OUTPUT_2); drawString (0.2f, 0.148f, textColor, HELP_OUTPUT_3); drawString (0.2f, 0.171f, textColor, HELP_OUTPUT_4); drawString (0.2f, 0.194f, textColor, HELP_OUTPUT_5); drawString (0.2f, 0.217f, textColor, HELP_OUTPUT_6); drawString (0.2f, 0.240f, textColor, HELP_OUTPUT_7); drawString (0.2f, 0.263f, textColor, HELP_OUTPUT_8); drawString (0.2f, 0.286f, textColor, HELP_OUTPUT_9); drawString (0.2f, 0.311f, textColor, HELP_OUTPUT_10); drawString (0.2f, 0.336f, textColor, HELP_OUTPUT_11); drawString (0.2f, 0.361f, textColor, HELP_OUTPUT_12); drawString (0.2f, 0.386f, textColor, HELP_OUTPUT_13); drawString (0.2f, 0.411f, textColor, HELP_OUTPUT_14); drawString (0.2f, 0.436f, textColor, HELP_OUTPUT_15); drawString (0.2f, 0.461f, textColor, HELP_OUTPUT_16); drawString (0.2f, 0.486f, textColor, HELP_OUTPUT_17); drawString (0.2f, 0.505f, textColor, HELP_OUTPUT_18); drawString (0.2f, 0.530f, textColor, HELP_OUTPUT_19); drawString (0.2f, 0.555f, textColor, HELP_OUTPUT_20); drawString (0.2f, 0.580f, textColor, HELP_OUTPUT_21); drawString (0.2f, 0.605f, textColor, HELP_OUTPUT_22); drawString (0.2f, 0.630f, textColor, HELP_OUTPUT_23); } /** * Setzt global eine Farbe! * @param color1,color2,color3 - RGB * @param alpha * @param shininess * @param emission */ void setColor (float color1, float color2, float color3, float alpha, float shininess, int emission) { float tmp[] = {0.0, 0.0, 0.0}; tmp[0] = color1; tmp[1] = color2; tmp[2] = color3; { /* Material */ float matAmbient[] = {0.0, 0.0, 0.0, 0.0}; float matBlack[]= {0.0, 0.0, 0.0, 0.0}; float matDiffuse[] = {0.0, 0.0, 0.0, 0.0}; float matSpecular[] = {0.0, 0.0, 0.0, 0.0}; float matShininess[] = { 0.0 }; matShininess[0] = shininess; matAmbient[0] = tmp[0]; matAmbient[1] = tmp[1]; matAmbient[2] = tmp[2]; matAmbient[3] = alpha; matSpecular[0] = tmp[0]; matSpecular[1] = tmp[1]; matSpecular[2] = tmp[2]; matSpecular[3] = alpha; matDiffuse[0] = tmp[0] - 0.7; matDiffuse[1] = tmp[1] - 0.7; matDiffuse[2] = tmp[2] - 0.7; matDiffuse[3] = alpha; /* Setzen der Material-Parameter */ glMaterialfv (GL_FRONT, GL_AMBIENT, matAmbient); glMaterialfv (GL_FRONT, GL_DIFFUSE, matDiffuse); glMaterialfv (GL_FRONT, GL_SPECULAR, matSpecular); glMaterialfv (GL_FRONT, GL_SHININESS, matShininess); if (emission) glMaterialfv (GL_FRONT, GL_EMISSION, matSpecular); else glMaterialfv (GL_FRONT, GL_EMISSION, matBlack); } } /** * Zeichnet Kugel mit mehr Parametern. * @param sliceCount - Anzahl der Unterteilungen * @param r - Radius */ void drawSphere (int sliceCount, double r) { GLUquadricObj * body; body = gluNewQuadric (); if (body == NULL) exit (1); /* Normalen fuer Quadrics berechnen lassen */ gluQuadricNormals (body, GLU_SMOOTH); gluSphere (body, r, sliceCount, sliceCount); gluDeleteQuadric (body); } /** * Zeichnet ein Quadrat mit der Kantenlaenge 1, das aus mehreren kleineren * Quadraten zusammen gesetzt ist. * @param subDivs Anzahl der Unterteilungsschritte der Kanten. */ static void drawSquare (GLint subDivs) { int x, y; for (y = 0; y < subDivs + 1; y++) { glNormal3f (0.0f, 0.0f, 1.0f); glBegin (GL_QUAD_STRIP); for (x = 0; x <= subDivs + 1; x++) { /* Texturkoordinate, gilt nicht, wenn Texturkoordinaten automatisch generiert werden. */ /*glTexCoord2f (x / (subDivs + 1.0f), y / (subDivs + 1.0f));*/ glVertex3f (-0.5f + x / (subDivs + 1.0f), 0.5f - y / (subDivs + 1.0f), 0.0f); /* Texturkoordinate, gilt nicht, wenn Texturkoordinaten automatisch generiert werden. */ /*glTexCoord2f (x / (subDivs + 1.0f), (y + 1) / (subDivs + 1.0f));*/ glVertex3f (-0.5f + x / (subDivs + 1.0f), 0.5f - (y + 1) / (subDivs + 1.0f), 0.0f); } glEnd (); } } /** * Zeichnet einen Wuerfel mit Kantenlaenge 1. * @param subDivs Anzahl der Unterteilungsschritte der Kanten. */ static void drawCube (unsigned int subDivs, GLfloat radius) { /* Frontflaeche */ glPushMatrix (); { glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix (); /* rechte Seitenflaeche */ glPushMatrix (); { glRotatef (90.0f, 0.0f, 1.0f, 0.0f); glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix (); /* Rueckseitenflaeche */ glPushMatrix (); { glRotatef (180.0f, 0.0f, 1.0f, 0.0f); glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix (); /* linke Seitenflaeche */ glPushMatrix (); { glRotatef (270.0f, 0.0f, 1.0f, 0.0f); glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix (); /* Deckelflaeche */ glPushMatrix (); { glRotatef (-90.0f, 1.0f, 0.0f, 0.0f); glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix (); /* Bodenflaeche */ /*glPushMatrix (); { glRotatef (90.0f, 1.0f, 0.0f, 0.0f); glTranslatef (0.0f, 0.0f, radius); drawSquare (subDivs); } glPopMatrix ();*/ } /** * Zeichnet ein Quadrat mit den Ecken p1,p2,p3,p4 in der Farbe color=1/0 * @param p1,p2,p3,p4 - Die Ecken * @param color - schwarz = 0 / weiß = 1 */ void drawVertex(CGPoint3f p1, CGPoint3f p2, CGPoint3f p3, CGPoint3f p4, int color) { if (color) setColor(1.0,1.0,1.0,G_Alpha,G_Shininess,G_Emission); else setColor(G_R,G_G,G_B,G_Alpha,G_Shininess,G_Emission); glBegin (GL_QUADS); { glVertex3f(p1[0],p1[1],p1[2]); glVertex3f(p2[0],p2[1],p2[2]); glVertex3f(p3[0],p3[1],p3[2]); glVertex3f(p4[0],p4[1],p4[2]); } glEnd(); } /** * Zeichnet den Boden */ void drawBottom(void) { CGPoint3f p1 = {0.0,GROUND_HEIGHT,0.0}, p2 = {WORLD_SIZE,GROUND_HEIGHT,0.0}, p3 = {WORLD_SIZE,GROUND_HEIGHT,WORLD_SIZE}, p4 = {0.0,GROUND_HEIGHT,WORLD_SIZE}; /*glDisable (GL_DEPTH_TEST);*/ /*glDisable(GL_CULL_FACE);*/ glPushMatrix (); { glTranslatef(-(WORLD_SIZE/2), -WORLD_SIZE/2.0+0.1,-(WORLD_SIZE/2)); /*setColor (0.0, 0.0, 0.0, 1.0, 40, 1);*/ drawRecursiveQuad(p1,p2,p3,p4,getQuadCount(),0); } glPopMatrix (); /*glEnable(GL_CULL_FACE);*/ /*glEnable (GL_DEPTH_TEST);*/ } /** * Zeichnet die Wände */ void drawSides(void) { glPushMatrix(); { G_R = 1.0; G_G = 0.0; G_B = 0.0; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(90,1,0,0); drawBottom(); } glPopMatrix(); glPushMatrix(); { G_R = 0.0; G_G = 1.0; G_B = 0.0; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(90,1,0,0); glRotatef(180,0,0,1); drawBottom(); } glPopMatrix(); glPushMatrix(); { G_R = 0.0; G_G = 0.0; G_B = 1.0; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(90,1,0,0); glRotatef(90,0,0,1); drawBottom(); } glPopMatrix(); glPushMatrix(); { G_R = 0.5; G_G = 0.5; G_B = 0.5; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(90,1,0,0); glRotatef(90,0,0,-1); drawBottom(); } glPopMatrix(); /* Oben! */ glPushMatrix(); { G_R = 1.0; G_G = 1.0; G_B = 0.0; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(180,1,0,0); drawBottom(); } glPopMatrix(); /* Unten! */ glPushMatrix(); { G_R = 0.0; G_G = 0.0; G_B = 0.0; G_Alpha = 1.0; G_Shininess = 40; G_Emission = 1; glRotatef(360,1,0,0); drawBottom(); } glPopMatrix(); } /** * Zeichnet die Welt */ void drawWorld() { glDisable(GL_CULL_FACE); glPushMatrix(); { setColor (WHITE, 1.0, 30.0, 0); /*glTranslatef(0,(30.0f)/2,0);*/ glScalef(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); drawCube(20,0.5f); } glPopMatrix(); glEnable(GL_CULL_FACE); } /** * Zeichnet die beiden Referenzkugeln */ void drawSpheres(void) { int i; glEnable(GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for (i=0;ipos[0],s->pos[1],s->pos[2]); setColor (s->color[0],s->color[1],s->color[2], SPHERE_TRANSPARENCY, 0.0, 1); glCullFace (GL_FRONT); drawSphere (SLICE_CNT, SPHERE_R); glCullFace (GL_BACK); drawSphere (SLICE_CNT, SPHERE_R); } glPopMatrix(); } glDisable (GL_BLEND); } void drawQuads(void) { int i; for (i=0;ipos[0],s->pos[1],s->pos[2]); glScalef(QUAD_SIDE, QUAD_SIDE, QUAD_SIDE); drawCube (1, 0.5); } glPopMatrix(); } } /** * Malt ein übergebenes Partikel in den Ursprung */ void drawOneParticle(Particle p, int suspensionPoint) { if (getParticleType() == sphere) { if (suspensionPoint) setColor (GREEN, 1.0, 0, 1); else setColor (RED, 1.0, 0, 1); glPushMatrix(); { glTranslatef(p->s[0],p->s[1],p->s[2]); drawSphere (4, 0.8); } glPopMatrix(); setColor (WHITE, 1.0, 0, 1); } } /** * Malt die Normale --> Up-Vektor des Partikels */ void drawParticleNormal (Particle p) { glBegin (GL_LINES); { CGVector3D up; /*printf ("scene: up: %f, %f, %f\n", p->up[0],p->up[1],p->up[2]);*/ up[0]=p->up[0]; up[1]=p->up[1]; up[2]=p->up[2]; normVector3D(up); glVertex3f(p->s[0],p->s[1],p->s[2]); glVertex3f(up[0]+p->s[0],up[1]+p->s[1],up[2]+p->s[2]); } glEnd (); } void drawFPS (void) { GLfloat textColor[3] = { 1.0f, 1.0f, 1.0f }; char * string = calloc ((strlen ("FPS = ") + 4), sizeof(char)); sprintf(string, "FPS = %d", getFPS()); drawString (0.6, 0.1, textColor, string); free (string); } void drawWaterSurface(void) { Water * water = getWaterList(); int i,j; /* Punkte anzeigen. */ glPointSize(1.0); for (i=0;i #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" void drawVertex(CGPoint3f p1, CGPoint3f p2, CGPoint3f p3, CGPoint3f p4, int color); void drawScene (void); void drawWaterSurface(void); void drawFPS (void); void drawSides(void); int initScene (void); void toggleWireframeMode (void); #endif ================================================ FILE: src/stringOutput.c ================================================ /** * @file * Einfache Funktion zum Zeichnen von Text fuer GLUT-Programme. */ /* ---- System Header einbinden ---- */ #include #include #include #ifdef MACOSX #include #else #include #endif /* ---- Eigene Header einbinden ---- */ #include "stringOutput.h" /** * Zeichnen einer Zeichfolge in den Vordergrund. Gezeichnet wird mit Hilfe von * glutBitmapCharacter(...). Kann wie printf genutzt werden. * @param x x-Position des ersten Zeichens 0 bis 1 (In). * @param y y-Position des ersten Zeichens 0 bis 1 (In). * @param color Textfarbe (In). * @param format Formatstring fuer die weiteren Parameter (In). */ void drawString (GLfloat x, GLfloat y, GLfloat * color, char *format, ...) { GLint matrixMode; /* Zwischenspeicher akt. Matrixmode */ va_list args; /* variabler Teil der Argumente */ char buffer[255]; /* der formatierte String */ char *s; /* Zeiger/Laufvariable */ va_start (args, format); vsprintf (buffer, format, args); va_end (args); /* aktuelle Zeichenfarbe (u.a. Werte) sichern */ glPushAttrib (GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT); /* aktuellen Matrixmode speichern */ glGetIntegerv (GL_MATRIX_MODE, &matrixMode); glMatrixMode (GL_PROJECTION); /* aktuelle Projektionsmatrix sichern */ glPushMatrix (); /* neue orthogonale 2D-Projektionsmatrix erzeugen */ glLoadIdentity (); gluOrtho2D (0.0, 1.0, 1.0, 0.0); glMatrixMode (GL_MODELVIEW); /* aktuelle ModelView-Matrix sichern */ glPushMatrix (); /* neue ModelView-Matrix zuruecksetzen */ glLoadIdentity (); /* Tiefentest ausschalten */ glDisable (GL_DEPTH_TEST); /* Licht ausschalten */ glDisable (GL_LIGHTING); /* Nebel ausschalten */ glDisable (GL_FOG); /* Blending ausschalten */ glDisable (GL_BLEND); /* Texturierung ausschalten */ glDisable (GL_TEXTURE_1D); glDisable (GL_TEXTURE_2D); /* glDisable (GL_TEXTURE_3D); */ /* neue Zeichenfarbe einstellen */ glColor4fv (color); /* an uebergebenene Stelle springen */ glRasterPos2f (x, y); /* Zeichenfolge zeichenweise zeichnen */ for (s = buffer; *s; s++) { glutBitmapCharacter (GLUT_BITMAP_HELVETICA_18, *s); } /* alte ModelView-Matrix laden */ glPopMatrix (); glMatrixMode (GL_PROJECTION); /* alte Projektionsmatrix laden */ glPopMatrix (); /* alten Matrixmode laden */ glMatrixMode (matrixMode); /* alte Zeichenfarbe und Co. laden */ glPopAttrib (); } ================================================ FILE: src/stringOutput.h ================================================ #ifndef _STRING_OUTPUT_H #define _STRING_OUTPUT_H /** * @file * Einfache Funktion zum Zeichnen von Text fuer GLUT-Programme. */ /* ---- System Header einbinden ---- */ #ifdef MACOSX #include #else #include #endif /* ---- Funktionsprototypen ---- */ /** * Zeichnen einer Zeichfolge in den Vordergrund. Gezeichnet wird mit Hilfe von * glutBitmapCharacter(...). Kann wie printf genutzt werden. * @param x x-Position des ersten Zeichens 0 bis 1 (In). * @param y y-Position des ersten Zeichens 0 bis 1 (In). * @param color Textfarbe (In). * @param format Formatstring fuer die weiteren Parameter (In). */ void drawString (GLfloat x, GLfloat y, GLfloat * color, char *format, ...); #endif ================================================ FILE: src/terrain.c ================================================ #include #include #include #include /* ---- Eigene Header einbinden ---- */ #include "terrain.h" #include "logic.h" #include "vector.h" #include "types.h" Terrain * G_TerrainList; GLuint * G_TerrainIndices; Terrain * G_TerrainCaustics; Terrain * getTerrainList(void){ return G_TerrainList; } Terrain * getTerrainCaustics(void) { return G_TerrainCaustics; } GLuint * getTerrainIndices (void) { return G_TerrainIndices; } void initTerrainIndices(void) { int i,j; int index = 0; for (i=0;i= TERRAIN_SIZE-1 || atJ < 1 || atJ >= TERRAIN_SIZE-1) { continue; } CGVector3D v1 = {G_TerrainList[i-TERRAIN_SIZE].x - G_TerrainList[i].x, G_TerrainList[i-TERRAIN_SIZE].y - G_TerrainList[i].y, G_TerrainList[i-TERRAIN_SIZE].z - G_TerrainList[i].z}; CGVector3D v2 = {G_TerrainList[i-1].x - G_TerrainList[i].x, G_TerrainList[i-1].y - G_TerrainList[i].y, G_TerrainList[i-1].z - G_TerrainList[i].z}; CGVector3D res1; crossProduct3D(res1, v1, v2); CGVector3D v3 = {G_TerrainList[i+TERRAIN_SIZE].x - G_TerrainList[i].x, G_TerrainList[i+TERRAIN_SIZE].y - G_TerrainList[i].y, G_TerrainList[i+TERRAIN_SIZE].z - G_TerrainList[i].z}; CGVector3D v4 = {G_TerrainList[i+1].x - G_TerrainList[i].x, G_TerrainList[i+1].y - G_TerrainList[i].y, G_TerrainList[i+1].z - G_TerrainList[i].z}; CGVector3D res2; crossProduct3D(res2, v3, v4); if (res1[1] < 0) { multiplyVectorScalar(res1, -1, &res1); } if (res2[1] < 0) { multiplyVectorScalar(res2, -1, &res2); } CGVector3D normal; addVectorVector(res1, res2, &normal); G_TerrainList[i].nx = normal[0]; G_TerrainList[i].ny = normal[1]; G_TerrainList[i].nz = normal[2]; G_TerrainCaustics[i].nx = G_TerrainList[i].nx; G_TerrainCaustics[i].ny = G_TerrainList[i].ny; G_TerrainCaustics[i].nz = G_TerrainList[i].nz; } } /** * Kubische Interpolation. */ double interpolateCube(double v0, double v1, double v2, double v3, double x) { double p = (v3 - v2) - (v0 - v1); double q = (v0 - v1) - p; double r = v2 - v0; double s = v1; return p*pow(x, 3) + q*pow(x, 2) + r*x + s; } /** * Kosinus-Interpolation. */ double interpolateCos(double a, double b, double x) { double ft = x * 3.1415927; double f = (1 - cos(ft)) * 0.5; return a*(1-f) + b*f; } /** * Erzeugt random-Noise-Wert zwischen 0..1 */ double noise(int x, int y) { long n = x + y * 57; n = (n<<13) ^ n; return (1.0 - ((n * (n*n*15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0); } /** * Erzeugt Noise... Etwas angepasst und smoothed. */ double smoothedNoise(float x, float y) { double corners = ( noise(x-1, y-1) + noise(x+1, y-1) + noise(x-1, y+1) + noise(x+1, y+1) ) / 16.0; double sides = ( noise(x-1, y ) + noise(x+1, y ) + noise(x , y-1) + noise(x , y+1) ) / 8; double center = noise(x,y) / 4; return corners + sides + center; } /** * Interpoliert das errechneten Noise, um perfekte fließende Übergänge zu erreichen (je nach Interpolationsart). */ double interpolatedNoise(float x, float y) { int intX = (int)x; double fractionalX = x - intX; int intY = (int)y; double fractionalY = y - intY; double v1 = smoothedNoise (intX , intY ); double v2 = smoothedNoise (intX + 1 , intY ); double v3 = smoothedNoise (intX , intY + 1 ); double v4 = smoothedNoise (intX + 1 , intY + 1 ); double i1 = interpolateCos(v1, v2, fractionalX); double i2 = interpolateCos(v3, v4, fractionalX); return interpolateCos(i1, i2, fractionalY); } /** * Berechnet einen Perlin-Noise-Wert für eine beliebige Position auf dem Feld! */ double perlinNoise2D(float x, float y) { double total = 0.0; double p = PERSISTENCE; int n = OCTAVES_COUNT; int i; for (i = 0;i max ? G_TerrainList[i].y : max; G_TerrainCaustics[i].x = G_TerrainList[i].x; G_TerrainCaustics[i].y = G_TerrainList[i].y; G_TerrainCaustics[i].z = G_TerrainList[i].z; G_TerrainCaustics[i].nx = G_TerrainList[i].nx; G_TerrainCaustics[i].ny = G_TerrainList[i].ny; G_TerrainCaustics[i].nz = G_TerrainList[i].nz; G_TerrainCaustics[i].s = G_TerrainList[i].s; G_TerrainCaustics[i].t = G_TerrainList[i].t; } printf ("Terrain-Height min: %f, max: %f\n", min, max); initTerrainIndices(); calcTerrainNormals(); } ================================================ FILE: src/terrain.h ================================================ #ifndef __TERRAIN_H__ #define __TERRAIN_H__ #define __DEBUG_GL_H__ /** * @file * Programmlogik und Datenhaltung * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" /* Maximale Ausdehnung (Mittig!) */ #define TERRAIN_SIZE 200 /* Wie groß das Noise abgebildet werden soll */ #define TERRAIN_DIMENSION 18.0 #define GAUSS_DIMENSION 10.0 #define TERRAIN_DISTANCE 1.0 #define PERSISTENCE 0.25 #define OCTAVES_COUNT 32 Terrain * getTerrainList(void); void initTerrain(void); Terrain * getTerrainCaustics(void); GLuint * getTerrainIndices (void); #endif ================================================ FILE: src/textureDepthFragmentShader.frag ================================================ #version 330 in vec2 texcoords; uniform sampler2D texsampler; out vec4 Color; float linearizeDepth (float depth) { float nearPlane = 0.1, farPlane = 1000.0; return (2*nearPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane)); } float linearizeDepthExtreme (float depth) { float nearPlane = 0.1, farPlane = 1000.0; float res = (2*nearPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane)); res = (res+0.3)*(res+0.3) - 0.5; return res; } void main(){ Color = vec4(linearizeDepthExtreme(texture(texsampler, texcoords).x)); } ================================================ FILE: src/textureFragmentShader.frag ================================================ #version 330 in vec2 texcoords; in vec3 normal; in float height; in vec3 causticNormal; uniform sampler2D texSand; uniform sampler2D texGrass; uniform sampler2D texRocks; uniform sampler2D texSnow; uniform sampler2D texForest; uniform sampler2D texTundra; out vec4 Color; float getLightValue(vec3 normalAt, vec3 sun, vec3 sun2, float lightUp) { float light = max(0,dot(normalAt, sun)); float light1 = max(0,dot(normalAt, sun2)); return mix(min(1,light + lightUp), min(1,light1 + lightUp), 0.5); } vec4 calcTexChange (float height, float min, float max, vec4 tex1, vec4 tex2) { float aspect = (height-min) / (max-min); return mix(tex1, tex2, aspect); } void main(){ float sandGrassFrom = -3.0, sandGrassTo = 3.0, grassForestFrom = 4.0, grassForestTo = 7.0, forestTundraFrom = 16.0, forestTundraTo = 25.0, tundraRocksFrom = 25.0, tundraRocksTo = 30.0, rocksSnowFrom = 40.0, rocksSnowTo = 60.0; vec3 sun = vec3(1,1,1); vec3 sun2 = vec3(-1,1,1); vec4 sand = texture(texSand , texcoords); vec4 grass = texture(texGrass, texcoords*3.0); vec4 forest = texture(texForest, texcoords*3.0); vec4 rocks = texture(texRocks, texcoords); vec4 tundra = texture(texTundra, texcoords*5.0); vec4 snow = texture(texSnow, texcoords*5.0); vec4 color; if (height < sandGrassFrom) { color = sand; } else if (height < sandGrassTo) { color = calcTexChange(height, sandGrassFrom, sandGrassTo, sand, grass); } else if (height < grassForestFrom) { color = grass; } else if (height < grassForestTo) { color = calcTexChange(height, grassForestFrom, grassForestTo, grass, forest); } else if (height < forestTundraFrom) { color = forest; } else if (height < forestTundraTo) { color = calcTexChange(height, forestTundraFrom, forestTundraTo, forest, tundra); } else if (height < tundraRocksFrom) { color = tundra; } else if (height < tundraRocksTo) { color = calcTexChange(height, tundraRocksFrom, tundraRocksTo, tundra, rocks); } else if (height < rocksSnowFrom) { color = rocks; } else if (height < rocksSnowTo) { color = calcTexChange(height, rocksSnowFrom, rocksSnowTo, rocks, snow); } else { color = snow; } color = color * getLightValue(normal, sun, sun2, 0.3); // Caustics //color = color * getLightValue(causticNormal, sun, sun2, 0.5); //float amount = dot(causticNormal, sun); //vec4 white = vec4(1,1,1,1); //vec4 caustics = mix(color, white, amount); Color = color; } ================================================ FILE: src/textureVertexShader.vert ================================================ #version 330 layout (location = 0) in vec3 vertPos; layout (location = 1) in vec2 tex; layout (location = 2) in vec3 normalIn; layout (location = 3) in vec3 causticNormal; uniform mat4 viewMatrix, projMatrix; out vec2 texcoords; out vec3 normal; out float height; out vec3 caustic; void main(){ gl_Position = projMatrix * viewMatrix * vec4(vertPos, 1.0); texcoords = tex; normal = normalize(normalIn); height = vertPos.y; caustic = normalize(causticNormal); } ================================================ FILE: src/types.h ================================================ #ifndef __TYPES_H__ #define __TYPES_H__ /** * @file * Typenschnittstelle. * Das Modul kapselt die Typdefinitionen und globalen Konstanten des Programms. * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif /* ---- Eigene Konstanten */ #define REFRACTION 30 #define GROUND_HEIGHT 0.3 #define CAMERA_X -50.1 #define CAMERA_Y 50.0 #define CAMERA_Z 75.0 #define CAMERA_SPEED 15.0 #define CAMERA_MOVEMENT_SPEED 4.0 #define CAMERA_ZOOM_SPEED 10.0 #define COUNTOWNTEX 2 #define WORLD_SIZE 150 #define SLICE_CNT 50 #define E 2.71828183 #define PI 3.14159265 #define EPS 0.0001 /** Anzahl der Aufrufe der Timer-Funktion pro Sekunde */ #define TIMER_CALLS_PS 120 /** Reihen des Images */ #define IMAGE_ROWS 128 #define IMAGE_COLS 128 #define SPHERE_MOVE_SPEED -35 #define SPHERE_R 80.0 #define SPHERE_TRANSPARENCY 0.8 #define SPHERE_CNT 0 #define QUAD_CNT 0 #define QUAD_SIDE 60 #define RED 0.7, 0.0, 0.0 #define BLUE 0.0, 0.0, 0.7 #define GREEN 0.0, 0.7, 0.0 #define BLACK 0.0, 0.0, 0.0 #define WHITE 1.0, 1.0, 1.0 #define GREY 0.4, 0.4, 0.4 #define YELLOW 0.7, 0.7, 0.0 /* Text */ /** Textausgabe, wenn das SPIEel zu ende ist, weil kein Stein mehr verfuegbar ist */ #define HELP_OUTPUT_1 "====== U'r blinded by pure AWESOMENESS!!!!! ======" #define HELP_OUTPUT_2 "|________________________________________________|" #define HELP_OUTPUT_3 "q/Q beendet das Spiel." #define HELP_OUTPUT_4 "r beginnt ein neues Spiel im Ausgangszustand." #define HELP_OUTPUT_5 "h/H oeffnet/schliesst den Hilfemodus." #define HELP_OUTPUT_6 "+/- Aendert die Anzahl der Quadrate auf dem Boden" #define HELP_OUTPUT_7 "n/N Kamera zum naechsten Partikel wechseln." #define HELP_OUTPUT_8 "m/M Kugeln in Bewegung setzten." #define HELP_OUTPUT_9 "t/T Textur wechseln." #define HELP_OUTPUT_10 "p/P Partikel einfrieren." #define HELP_OUTPUT_11 "f/F Ansicht der Partikel wechseln." #define HELP_OUTPUT_12 "b Kugeln bewegen sich nach Bezier." #define HELP_OUTPUT_13 "B Bezier-Kurven der Kugeln werden angezeigt." #define HELP_OUTPUT_14 "s/S Schatten zeichnen an/aus." #define HELP_OUTPUT_15 "k/K Kamera-Modus wechseln." #define HELP_OUTPUT_16 "v/V Verfolger-Modus an/aus." #define HELP_OUTPUT_17 "x/X Abstand fuer Bezier-Kontrollpunkte erhoehen." #define HELP_OUTPUT_18 "y/Y Abstand fuer Bezier-Kontrollpunkte verkleinern." #define HELP_OUTPUT_19 "f1 Wireframe an/aus." #define HELP_OUTPUT_20 "f2 Licht an/aus." #define HELP_OUTPUT_21 "f3 Texturen an/aus." #define HELP_OUTPUT_22 "Maus + rechte Maustaste Abstand zum Mittelpunkt." #define HELP_OUTPUT_23 "Maus + linke Maustaste Bewegung im Raum." /* Tastatur */ /** Keyboardtaste ESC definieren */ #define ESC 27 /** Keyboardtaste SPACE definieren */ #define SPACE 32 /** Datentyp fuer den aktuellen SPIEelmodus */ enum e_gameIntiType { OFF, ON }; typedef enum e_gameIntiType InitType; /** Mausereignisse. */ enum e_MouseEventType { mouseButton, mouseMotion, mousePassiveMotion }; /** Datentyp fuer Mausereignisse. */ typedef enum e_MouseEventType CGMouseEventType; /** Mausereignisse. */ enum e_MouseInterpretType { NONE, MOVE, ZOOM}; /** Datentyp fuer Mausereignisse. */ typedef enum e_MouseInterpretType MouseInterpretType; /** Datentyp fuer die Texturart */ enum e_textureType { NORMALTEXTURE, CHECKER, DIAGONAL }; /** Datentyp die Texturart */ typedef enum e_textureType textureType; /** Datentyp fuer den aktuellen SPIEelmodus */ enum e_gameModi { normal, help }; typedef enum e_gameModi GameMode; /** Datentyp fuer die Verlaengerung/Verkuerzung des Kameravektors */ enum e_cameraVector { closer, further }; typedef enum e_cameraVector CameraVector; /** Datentyp fuer die Richtungsaenderungen */ enum e_gameDirection {left, right, up, down}; typedef enum e_gameDirection Directions; /** Punkt im 3D-Raum (homogene Koordinaten) */ typedef GLfloat CGPoint4f[4]; typedef GLfloat CGPoint3f[3]; typedef CGPoint3f CGColor; /** Datentyp fuer einen Vektor */ typedef double Vector4D[4]; typedef Vector4D Punkt4D; /** Vektor im 3D-Raum */ typedef GLfloat CGVector3D[3]; typedef double Vertex[6]; typedef int Movement[3]; typedef double VertexTexture[2]; enum e_particleType {line, sphere}; typedef enum e_particleType ParticleType; typedef struct { GLfloat x,y,z; GLfloat s,t; GLfloat nx, ny, nz; GLint fix; } Water; typedef struct { GLfloat x,y,z; GLfloat s,t; GLfloat nx, ny, nz; } Terrain; /** Kugeln */ typedef struct X * Spheres; struct X { /* Position im Raum */ CGPoint3f pos; /* Richtungsvektor, Geschwindigkeit in eine Richtung */ CGVector3D newPos; /* Farbe */ CGVector3D color; /* Bezier */ Vertex * interpolatedPoints; /* Bezier */ Vertex * interpolatedPointsAll; Vertex * controlPoints; /* Bezier t */ double t; }; /** Kugeln */ typedef struct Z * Quads; struct Z { /* Position im Raum */ CGPoint3f pos; }; /** Partikel */ typedef struct Y * Particle; struct Y { /* Position im Raum */ CGPoint3f s; /* Geschwindigkeitsvektor */ CGVector3D v; /* Beschleunigungsvektor */ CGVector3D a; /* Kraft - intern */ CGVector3D f; /* Masse */ double m; /* Noch was? */ /* Upvektor */ CGVector3D up; }; #endif ================================================ FILE: src/vector.c ================================================ /** * @file * Hier ist die Datenhaltung und Programmlogik * * @author Tilman Nedele, Maurice Tollmien */ /* ---- System Header einbinden ---- */ #include #include #include #include #include #include #ifdef MACOSX #include #else #include #endif /* ---- Eigene Header einbinden ---- */ #include "types.h" /** * Printet einen Vector aus. */ void printVector (CGVector3D a) { int i; printf("\nprintVector:\n"); for (i=0;i<3;i++) printf("%.1f\n", a[i]); printf("\n"); } /** * Konvertierungsfunktion, * wandelt drei Koordinaten in den dazugehörigen Vektor um * @param x * @param y * @param z */ void toVector3D(CGVector3D vector, GLfloat x, GLfloat y, GLfloat z) { vector[0] = x; vector[1] = y; vector[2] = z; } /** * Berechnet die Länge es Vektors * @param v *@return float */ float vectorLength3D(CGVector3D vector) { return sqrt((vector[0]*vector[0])+ (vector[1]*vector[1])+ (vector[2]*vector[2])); } /** * Normiert eine Vektor * @param v der zu normierende Vektor * @return der normierte Vektor */ void normVector3D(CGVector3D vector) { float l = vectorLength3D(vector); if (l != .0f) toVector3D(vector, vector[0]/l, vector[1]/l, vector[2]/l); } /** * Berechnet das Kreuzprodukt zweier Vektoren * @param * @param * @return */ void crossProduct3D(CGVector3D product, CGVector3D a, CGVector3D b) { toVector3D(product, (a[1]*b[2] - a[2]*b[1]), (a[2]*b[0] - a[0]*b[2]), (a[0]*b[1] - a[1]*b[0])); } /** * Multipliziert zwei Vektoren miteinander (Skalarprodukt) */ double multiplyVectorVector (CGVector3D a, CGVector3D b) { int i; double res = 0.0; for (i=0;i<3;i++) res += a[i]*b[i]; return res; } /** * Multipliziert einen Vektor mit einem Skalar. */ void multiplyVectorScalar (CGVector3D a, double s, CGVector3D * res) { int i; for (i=0;i<3;i++) (*res)[i] = a[i]*s; } double scalarProduct (CGVector3D a, CGVector3D b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } /** * Zieht b von a ab, also: a-b */ void subtractVectorVector (CGVector3D a, CGVector3D b, CGVector3D * res) { int i; for (i=0;i<3;i++) (*res)[i] = a[i] - b[i]; } /** * Teilt den Vector a durch s. */ void divideVectorScalar (CGVector3D a, double s, CGVector3D * res) { int i; for (i=0;i<3;i++) (*res)[i] = a[i] / s; } /** * Addiert a und b und schreibt das Ergebnis in res. */ void addVectorVector (CGVector3D a, CGVector3D b, CGVector3D * res) { int i; for (i=0;i<3;i++) (*res)[i] = a[i] + b[i]; } /** * Wandelt eine Zahl (Grad) in Radiant. * deg muss im Wertebereich 0..359 liegen! */ double degToRad (double deg) { return deg*PI/180.0; } /** * Wandelt eine Zahl (Radiant) in Grad um. * deg muss im Wertebereich 0..PI liegen! */ double radToDeg (double rad) { return rad*180.0/PI; } /** * Berechnet den Winkel zwischen zwei Vektoren und gibt das Ergebnis in * ° zurück (nicht radiant!). */ double angleVectorVector (CGVector3D a, CGVector3D b) { return radToDeg (acos (multiplyVectorVector (a, b) / (vectorLength3D(a)*vectorLength3D(b)))); } ================================================ FILE: src/vector.h ================================================ #ifndef __VECTOR_H__ #define __VECTOR_H__ #define __DEBUG_GL_H__ /** * @file * Programmlogik und Datenhaltung * * @author Maurice Tollmien */ /* ---- System Header einbinden ---- */ #ifdef WIN32 #include #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" /* eig. Funktionen */ /** * Konvertierungsfunktion, * wandelt drei Koordinaten in den dazugehörigen Vektor um * @param x * @param y * @param z */ void toVector3D(CGVector3D vector, GLfloat x, GLfloat y, GLfloat z); /** * Berechnet die Länge es Vektors * @param v *@return float */ float vectorLength3D(CGVector3D vector); /** * Normiert eine Vektor * @param v der zu normierende Vektor * @return der normierte Vektor */ void normVector3D(CGVector3D vector); /** * Berechnet das Kreuzprodukt zweier Vektoren * @param * @param * @return */ void crossProduct3D(CGVector3D product, CGVector3D a, CGVector3D b); double multiplyVectorVector (CGVector3D a, CGVector3D b); void multiplyVectorScalar (CGVector3D a, double s, CGVector3D * res); void subtractVectorVector (CGVector3D a, CGVector3D b, CGVector3D * res); void divideVectorScalar (CGVector3D a, double s, CGVector3D * res); void addVectorVector (CGVector3D a, CGVector3D b, CGVector3D * res); void printVector (CGVector3D a); double angleVectorVector (CGVector3D a, CGVector3D b); double radToDeg (double rad); double degToRad (double deg); double scalarProduct (CGVector3D a, CGVector3D b); #endif ================================================ FILE: src/water.c ================================================ #include #include #include #include /* ---- Eigene Header einbinden ---- */ #include "water.h" #include "particle.h" #include "logic.h" #include "vector.h" #include "types.h" #include "terrain.h" Water * G_WaterList; Water * G_TmpWaterList; float ** G_V; GLuint * G_WaterIndices; int normalList = 1; int G_IsMoving = 1; int G_randomize = 0; Water * getWaterList(void){ return G_WaterList; } void calcWaterAttributes (double interval) { int i,j; double f; if (G_IsMoving) { for (i=0;i 0.1) { printf ("Wasser: fix=%d, Y now=%f, Y init=%f\n", G_WaterList[i].fix, G_WaterList[i].y, (double)WATER_HEIGHT_INIT); } if (atI == 0 || atI == WORLD_SIZE-1 || atJ == 0 || atJ == WORLD_SIZE-1 ) { continue; } f = WATER_SPEED * WATER_SPEED * ( G_WaterList[i - WORLD_SIZE].y + G_WaterList[i + WORLD_SIZE].y + G_WaterList[i + 1].y + G_WaterList[i - 1].y - 4 * G_WaterList[i].y ) / WATER_WIDTH; G_V[atI][atJ] += f * interval; if (!G_WaterList[i].fix) G_TmpWaterList[i].y = G_WaterList[i].y + G_V[atI][atJ] * interval; else G_TmpWaterList[i].y = WATER_HEIGHT_INIT; if (G_randomize) { G_TmpWaterList[i].y = WATER_HEIGHT_INIT + WATER_DISTORTION - WATER_DISTORTION; G_WaterList[i].y = WATER_HEIGHT_INIT + WATER_DISTORTION - WATER_DISTORTION; } CGVector3D v1 = {G_WaterList[i-WORLD_SIZE].x - G_WaterList[i].x, G_WaterList[i-WORLD_SIZE].y - G_WaterList[i].y, G_WaterList[i-WORLD_SIZE].z - G_WaterList[i].z}; CGVector3D v2 = {G_WaterList[i-1].x - G_WaterList[i].x, G_WaterList[i-1].y - G_WaterList[i].y, G_WaterList[i-1].z - G_WaterList[i].z}; CGVector3D res1; crossProduct3D(res1, v1, v2); CGVector3D v3 = {G_WaterList[i+WORLD_SIZE].x - G_WaterList[i].x, G_WaterList[i+WORLD_SIZE].y - G_WaterList[i].y, G_WaterList[i+WORLD_SIZE].z - G_WaterList[i].z}; CGVector3D v4 = {G_WaterList[i+1].x - G_WaterList[i].x, G_WaterList[i+1].y - G_WaterList[i].y, G_WaterList[i+1].z - G_WaterList[i].z}; CGVector3D res2; crossProduct3D(res2, v3, v4); if (res1[1] < 0) { multiplyVectorScalar(res1, -1, &res1); } if (res2[1] < 0) { multiplyVectorScalar(res2, -1, &res2); } CGVector3D normal; addVectorVector(res1, res2, &normal); G_TmpWaterList[i].nx = normal[0]; G_TmpWaterList[i].ny = normal[1]; G_TmpWaterList[i].nz = normal[2]; /* Caustics durch die Normalen des Wasser auf der Bodenfläche. */ int waterTerrainOffset = (TERRAIN_SIZE - WORLD_SIZE)/2; Terrain * terrainCaustics = getTerrainCaustics(); /*terrainCaustics[(atI + waterTerrainOffset) * TERRAIN_SIZE + (atJ + waterTerrainOffset)].nx = normal[0]; terrainCaustics[(atI + waterTerrainOffset) * TERRAIN_SIZE + (atJ + waterTerrainOffset)].ny = normal[1]; terrainCaustics[(atI + waterTerrainOffset) * TERRAIN_SIZE + (atJ + waterTerrainOffset)].nz = normal[2]; */ } Water * tmp; tmp = G_TmpWaterList; G_TmpWaterList = G_WaterList; G_WaterList = tmp; } G_randomize = 0; } /** * Guckt, wo/ob Wasserpunkte einen Mindestabstand zu Landpunkten unterschreiten * und setzt diese auf fix, sodass quasi ein Wasserrand entsteht. */ void calcFixWaterPoints(Terrain * terrain) { int w,t; double eps = 1.0; for (t = 0; t < TERRAIN_SIZE*TERRAIN_SIZE; t++) { for (w = 0; w < WORLD_SIZE*WORLD_SIZE; w++) { if (fabs(terrain[t].x - G_WaterList[w].x) < eps && fabs(terrain[t].y - G_WaterList[w].y) < eps && fabs(terrain[t].z - G_WaterList[w].z) < eps ) { G_WaterList[w].fix = 1; G_WaterList[w].y = WATER_HEIGHT_INIT; } } } } void setRandomize(void) { G_randomize = 1; } void pushSomeWaterDown(void) { int i,j; for (i=WORLD_SIZE/2-4;i #endif #ifdef MACOSX #include #else #include #endif #include #include #include "types.h" #include "terrain.h" #define WATER_HEIGHT_INIT 0 #define WATER_SPEED 3 #define WATER_WIDTH 1 #define WATER_DISTORTION (rand()%1000) / 4000.0 Water * getWaterList(void); void initWater(void); void calcWaterAttributes (double interval); void pushSomeWaterDown(void); void toggleWaterMovement(void); GLuint * getWaterIndices (void); void calcFixWaterPoints(Terrain * terrain); void setRandomize(void); #endif ================================================ FILE: src/waterFragmentShader.frag ================================================ #version 330 in vec3 pos_vec; in vec3 normal; in vec3 pos_cam; in vec3 backgroundColor; in float height; uniform sampler2D texsampler; uniform sampler2D texsamplerDepth; uniform samplerCube texsamplerCube; uniform mat4 viewMatrix, projMatrix; out vec4 Color; float linearizeDepth2 (float depth) { float nearPlane = 0.1, farPlane = 1000.0; return (2*nearPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane)); } float linearizeDepth (float depth) { float nearPlane = 0.1, farPlane = 1000.0; float res = (2*nearPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane)); res = (res+0.3)*(res+0.3) - 0.5; return res; } // Umwandlung einer Weltkoordinate in Screenkoordinate! vec3 getScreenPos (vec3 worldPos) { vec4 screenPos = projMatrix * viewMatrix * vec4(worldPos, 1.0); vec3 screenPos3 = screenPos.xyz / screenPos.w; return (screenPos3 + vec3(1.0)) / 2.0; } vec3 cubeMapRefl (vec3 reflectionWorld) { return texture(texsamplerCube, reflectionWorld).rgb; } vec3 cubeMapRefr (vec3 refractionWorld) { return texture(texsamplerCube, refractionWorld).rgb; } // Tiefe des Wassers an dem Fragment: vec3 calcWaterDependentDarkness(vec3 color, float maxDepth) { // zwischen 0 und 1. vec3 screenPos = getScreenPos(pos_vec); vec2 screenTexPos = screenPos.xy; float texDepth = texture(texsamplerDepth, screenTexPos).x; float worldDepth = screenPos.z; float depth = worldDepth - texDepth; vec3 black = vec3(0.0); /*if (depth <= 1.0 && depth >= 0.0) { return vec3(1,0,0); } else return vec3(1.0);*/ return vec3(texDepth); return mix(black, color, 1.0-depth); } vec3 raytrace(in vec3 reflectionWorld, in int maxCount, in float stepSize) { vec3 color = vec3(1.0); vec3 testVec = pos_vec; vec3 reflectionVector = reflectionWorld * stepSize; vec3 screenPos = getScreenPos(testVec); vec2 screenTexPos = screenPos.xy; float texDepth = texture(texsamplerDepth, screenTexPos).x; float worldDepth = screenPos.z; bool run = true; int count = 0; while (run) { texDepth = texture(texsamplerDepth, screenTexPos).x; worldDepth = screenPos.z; if (texDepth <= worldDepth) { color = texture(texsampler, screenTexPos).rgb; break; } testVec = testVec + reflectionVector; screenPos = getScreenPos(testVec); screenTexPos = screenPos.xy; count = count+1; run = screenTexPos.x < 1.0 && screenTexPos.x >= 0.0 && screenTexPos.y < 1.0 && screenTexPos.y >= 0.0 && count < maxCount; } if (!run) { color = cubeMapRefl(testVec); // Cheating //color = vec3(0,1,1); } return color; } float getFresnelFactor (void) { float fresnelPower = 3; float fresnelScale = 5.0; float fresnelBias = 0.05373; return fresnelBias + fresnelScale * pow(1 + dot(normalize(pos_vec - pos_cam), normal), fresnelPower); } float calcStepSize(float stepSize, float max, vec3 n, vec3 cam) { float scalarProduct = dot(n, cam); float res = 0.0; res = (1.0 - scalarProduct) * (max-stepSize); return res + stepSize; } void main(){ const int maxCount = 250; const float ratio = 1.0 / 1.3333; float stepSize = 20.0; float maxStepSize = 400.0; float maxDepth = 0.9; vec4 black = vec4(0,0,0,0); vec3 eyePosition = normalize(pos_vec - pos_cam); vec3 reflectionWorld = normalize (reflect(eyePosition, normal)); vec3 refractionWorld = normalize (refract(eyePosition, normal, ratio)); // Nicht physikalisch korrekte Anpassung, dass mehr Geometrie gespiegelt wird! reflectionWorld = reflectionWorld + vec3(0, -0.15, 0); // Stepsize anpassen an das Verhältnis der Normalen zum Blickvektor stepSize = calcStepSize(stepSize, maxStepSize, -normal, eyePosition); vec3 reflectedColor = raytrace(reflectionWorld, maxCount, stepSize); vec3 refractedColor = raytrace(refractionWorld, maxCount, stepSize); //refractedColor = calcWaterDependentDarkness(refractedColor, maxDepth); vec4 screenSpaceReflection = vec4(reflectedColor, 1.0); vec4 screenSpaceRefraction = vec4(refractedColor, 1.0); screenSpaceRefraction = mix(black, screenSpaceRefraction, 0.5); vec4 tmpColor = mix (screenSpaceRefraction, screenSpaceReflection, getFresnelFactor()); tmpColor = mix (black, tmpColor, 0.8); // Wenn das Wasser tief wird. if (height < 0.0) { float aspect = (height+8.0) / 8.0; tmpColor = mix(black, tmpColor, aspect); tmpColor = vec4(0.0); } Color = tmpColor; //Color = screenSpaceReflection; //Color = screenSpaceRefraction; } ================================================ FILE: src/waterVertexShader.vert ================================================ #version 330 layout (location = 0) in vec3 vertPos; layout (location = 1) in vec3 normal_in; layout (location = 2) in vec3 terrain; uniform mat4 viewMatrix, projMatrix; uniform vec3 cameraPos; out vec3 pos_vec; out vec3 normal; out vec3 pos_cam; out float height; void main(){ vec3 newPos = vec3(vertPos - pos_cam); gl_Position = projMatrix * viewMatrix * vec4(vertPos, 1.0); pos_vec = vertPos; normal = normalize(normal_in); pos_cam = cameraPos; height = terrain.y; }