diff --git a/Makefile b/Makefile index 9769728aa..eef1d9f87 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,8 @@ +# Master Makefile for TSGL + +# ***************************************************** +# Variables to control Makefile operation + AR=ar CC=g++ RM=rm -f @@ -6,14 +11,13 @@ PREFIX=/usr/local SRC_PATH=src/TSGL/ TESTS_PATH=src/tests/ +EXAMPLES_PATH=src/examples/ OBJ_PATH=build/ VPATH=SRC_PATH:TESTS_PATH:OBJ_PATH HEADERS := $(wildcard src/TSGL/*.h) SOURCES := $(wildcard src/TSGL/*.cpp) -TESTS := $(wildcard src/tests/*.cpp) OBJS := $(patsubst src/TSGL/%.cpp,build/TSGL/%.o,${SOURCES}) -TESTOBJS := $(patsubst src/tests/%.cpp,build/tests/%.o,${TESTS}) NOWARN := -Wno-unused-parameter -Wno-unused-function -Wno-narrowing UNAME := $(shell uname) @@ -21,16 +25,27 @@ ifeq ($(UNAME), Linux) OS_LFLAGS := -lpthread OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ OS_EXTRA_LIB := -L/usr/lib - OS_GLFW := glfw OS_GL := -lGL + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x +endif + +ifeq ($(UNAME), CYGWIN_NT-10.0) + OS_LFLAGS := -lpthread + OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ + OS_EXTRA_LIB := -L/usr/lib + OS_GL := -lGL + OS_OMP := -lgomp -fopenmp + OS_COMPILER := -std=gnu++11 endif ifeq ($(UNAME), Darwin) OS_LFLAGS := -framework Cocoa -framework OpenGl -framework IOKit -framework Corevideo OS_LDIRS := - OS_EXTRA_LIB := - OS_GLFW := glfw + OS_EXTRA_LIB := OS_GL := + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x endif CXXFLAGS=-O3 -g3 -ggdb3 \ @@ -45,11 +60,11 @@ CXXFLAGS=-O3 -g3 -ggdb3 \ -I/opt/AMDAPP/include/ \ -I/usr/include/c++/4.6/ \ -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ - -I/usr/lib/gcc/x86_64-linux-gnu/4.6/include/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ -I/usr/include/freetype2 \ -I/usr/include/freetype2/freetype \ -I./ \ - -std=c++0x -fopenmp \ + $(OS_COMPILER) -fopenmp \ ${NOWARN} -fpermissive # -pedantic-errors @@ -58,89 +73,69 @@ LFLAGS=-Llib/ \ ${OS_EXTRA_LIB} \ -L/usr/X11/lib/ \ ${OS_LDIRS} \ - -ltsgl -lfreetype -lGLEW -l${OS_GLFW} \ - -lX11 ${OS_GL} -lXrandr -Xpreprocessor -fopenmp -lomp -I"$(brew --prefix libomp)/include" \ + -ltsgl -lfreetype -lGLEW -lglfw \ + -lX11 ${OS_GL} -lXrandr -Xpreprocessor $(OS_OMP) -I"$(brew --prefix libomp)/include" \ ${OS_LFLAGS} DEPFLAGS=-MMD -MP -BINARIES= \ - bin/test_specs \ - bin/testAlphaRectangle \ - bin/testArrows \ - bin/testAura \ - bin/testBallroom \ - bin/testBlurImage \ - bin/testCalcPi \ - bin/testColorPoints \ - bin/testColorWheel \ - bin/testConcavePolygon \ - bin/testConstructors \ - bin/testConway \ - bin/testCosineIntegral \ - bin/testDumbSort \ - bin/testFireworks \ - bin/testForestFire \ - bin/testFunction \ - bin/testGetPixels \ - bin/testGradientWheel \ - bin/testGraydient \ - bin/testGreyscale \ - bin/testHighData \ - bin/testImage \ - bin/testImageCart \ - bin/testInverter \ - bin/testLangton \ - bin/testLineChain \ - bin/testLineFan \ - bin/testMandelbrot \ - bin/testMouse \ - bin/testNewtonPendulum \ - bin/testPhilosophers \ - bin/testProducerConsumer \ - bin/testPong \ - bin/testProgressBar \ - bin/testProjectiles \ - bin/testReaderWriter \ - bin/testRotation \ - bin/testScreenshot \ - bin/testSeaUrchin \ - bin/testSmartSort \ - bin/testSpectrogram \ - bin/testSpectrum \ - bin/testStar \ - bin/testText \ - bin/testTextCart \ - bin/testTextTwo \ - bin/testUnits \ - bin/testVoronoi \ +TESTFLAGS = -lsrc/TSGL/ + +# **************************************************** +# Targets needed to bring all files up to date #Use make tsgl to make only the library files -all: dif tsgl tests docs tutorial +all: dif tsgl docs tutorial debug: dif tsgl tests dif: build/build #This may change (for the Mac installer)! +#tsgl +ifeq ($(UNAME), Linux) tsgl: lib/libtsgl.a lib/libtsgl.so +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +tsgl: lib/libtsgl.a lib/libtsgl.dll +endif +ifeq ($(UNAME), Darwin) +tsgl: lib/libtsgl.a lib/libtsgl.so +endif -tests: ${BINARIES} +# must run 'make' before 'make tests' and 'make examples' +tests: $(TESTS_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build + +examples: $(EXAMPLES_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build docs: docs/html/index.html tutorial: tutorial/docs/html/index.html -cleanall: clean cleandocs +cleanall: clean cleantests cleanexamples cleandocs clean: $(RM) -r bin/* build/* lib/* tutorial/docs/html/* *~ *# *.tmp + $(MAKE) cleantests + $(MAKE) cleanexamples + +cleantests: + (cd $(TESTS_PATH) && $(MAKE) clean) + +cleanexamples: + (cd $(EXAMPLES_PATH) && $(MAKE) clean) cleandocs: $(RM) -r docs/html/* # -include build/*.d +#install +ifeq ($(UNAME), Linux) install: test -d $(PREFIX) || mkdir $(PREFIX) test -d $(PREFIX)/lib || mkdir $(PREFIX) @@ -148,18 +143,44 @@ install: install -m 0644 lib/libtsgl.a $(PREFIX)/lib install -m 0755 lib/libtsgl.so $(PREFIX)/lib cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.dll $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), Darwin) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.so $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include + cp -r stb $(PREFIX)/include +endif build/build: ${HEADERS} ${SOURCES} ${TESTS} @echo 'Files that changed:' @echo $(patsubst src/%,%,$?) +#lib/libtsgl.* ifeq ($(UNAME), Linux) lib/libtsgl.so: ${OBJS} @echo 'Building $(patsubst lib/%,%,$@)' $(CC) -shared -o $@ $? @touch build/build endif - +ifeq ($(UNAME), CYGWIN_NT-10.0) +lib/libtsgl.dll: ${OBJS} + @echo 'Building $(patsubst lib/%,%,$@)' + $(CC) -shared -o $@ $? $(LFLAGS) + @touch build/build +endif ifeq ($(UNAME), Darwin) lib/libtsgl.so: ${OBJS} @echo 'Building $(pathsubst lib/%,%,$@)' @@ -173,44 +194,6 @@ lib/libtsgl.a: ${OBJS} $(AR) -r $@ $? @touch build/build -#List additional dependencies for test binaries -bin/testConway: build/tests/Conway/LifeFarm.o -bin/testFireworks: build/tests/Fireworks/Arc.o \ - build/tests/Fireworks/Dot.o \ - build/tests/Fireworks/Firework.o -bin/testInverter: build/tests/ImageInverter/ImageInverter.o -bin/testLangton: build/tests/Langton/AntFarm.o build/tests/Langton/LangtonAnt.o -bin/testMandelbrot: build/tests/Mandelbrot/Mandelbrot.o \ - build/tests/Mandelbrot/GradientMandelbrot.o \ - build/tests/Mandelbrot/Buddhabrot.o \ - build/TSGL/VisualTaskQueue.o \ - build/tests/Mandelbrot/Julia.o \ - build/tests/Mandelbrot/Nova.o -bin/testPhilosophers: build/tests/DiningPhilosophers/Philosopher.o \ - build/tests/DiningPhilosophers/Table.o -bin/testPong: build/tests/Pong/Pong.o build/tests/Pong/Paddle.o build/tests/Pong/Ball.o -bin/testProducerConsumer: build/tests/ProducerConsumer/Producer.o \ - build/tests/ProducerConsumer/Consumer.o \ - build/tests/ProducerConsumer/Thread.o \ - build/tests/ProducerConsumer/PCThread.o -bin/testReaderWriter: build/tests/ReaderWriter/FLock.o \ - build/tests/ReaderWriter/Lock.o \ - build/tests/ReaderWriter/Reader.o \ - build/tests/ReaderWriter/RLock.o \ - build/tests/ReaderWriter/RWThread.o \ - build/tests/ReaderWriter/Thread.o \ - build/tests/ReaderWriter/WLock.o \ - build/tests/ReaderWriter/Writer.o -bin/testSeaUrchin: build/tests/SeaUrchin/SeaUrchin.o -bin/testVoronoi: build/tests/Voronoi/Voronoi.o build/tests/Voronoi/ShadedVoronoi.o - -#General compilation recipes for test binaries (appended to earlier dependencies) -bin/test%: build/tests/test%.o lib/libtsgl.a - mkdir -p bin - @echo 'Building $(patsubst bin/%,%,$@)' - $(CC) $^ -o $@ $(LFLAGS) - @touch build/build - build/%.o: src/%.cpp @echo "" @tput setaf 3; @@ -221,7 +204,6 @@ build/%.o: src/%.cpp $(CC) -c -fpic $(CXXFLAGS) $(DEPFLAGS) -o "$@" "$<" - #Doxygen stuff docs/html/index.html: ${HEADERS} doxyfile @echo "" @@ -241,5 +223,5 @@ tutorial/docs/html/index.html: ${HEADERS} tutDoxyFile mkdir -p tutorial/docs doxygen tutDoxyFile -.PHONY: all debug clean tsgl tests docs tutorial dif +.PHONY: all debug clean tsgl docs tutorial dif .SECONDARY: ${OBJS} ${TESTOBJS} $(OBJS:%.o=%.d) diff --git a/assets/pics/launch.bmp b/assets/pics/launch.bmp new file mode 100644 index 000000000..0e397c41b Binary files /dev/null and b/assets/pics/launch.bmp differ diff --git a/assets/pics/lowDimImage.jpg b/assets/pics/lowDimImage.jpg new file mode 100644 index 000000000..34171ba09 Binary files /dev/null and b/assets/pics/lowDimImage.jpg differ diff --git a/assets/shaders/shape.fs b/assets/shaders/shape.fs new file mode 100644 index 000000000..d435a46e9 --- /dev/null +++ b/assets/shaders/shape.fs @@ -0,0 +1,9 @@ +#version 330 core +out vec4 FragColor; + +in vec4 color; + +void main() +{ + FragColor = color; +} \ No newline at end of file diff --git a/assets/shaders/shape.vs b/assets/shaders/shape.vs new file mode 100644 index 000000000..186f588af --- /dev/null +++ b/assets/shaders/shape.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec4 aColor; + +out vec4 color; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + color = aColor; +} \ No newline at end of file diff --git a/assets/shaders/text.fs b/assets/shaders/text.fs new file mode 100644 index 000000000..f3112a712 --- /dev/null +++ b/assets/shaders/text.fs @@ -0,0 +1,12 @@ +#version 330 core +in vec2 TexCoords; +out vec4 FragColor; + +uniform sampler2D text; +uniform vec4 textColor; + +void main() +{ + vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); + FragColor = textColor * sampled; +} \ No newline at end of file diff --git a/assets/shaders/text.vs b/assets/shaders/text.vs new file mode 100644 index 000000000..c9601998e --- /dev/null +++ b/assets/shaders/text.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoords; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + TexCoords = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/assets/shaders/texture_simple.fs b/assets/shaders/texture_simple.fs new file mode 100644 index 000000000..ce447ac3e --- /dev/null +++ b/assets/shaders/texture_simple.fs @@ -0,0 +1,11 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D texture1; + +void main() +{ + FragColor = texture(texture1, TexCoords); +} \ No newline at end of file diff --git a/assets/shaders/texture_simple.vs b/assets/shaders/texture_simple.vs new file mode 100644 index 000000000..9ce732af5 --- /dev/null +++ b/assets/shaders/texture_simple.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoords; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + TexCoords = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/install-cygwin.sh b/install-cygwin.sh new file mode 100644 index 000000000..bfe19f7b2 --- /dev/null +++ b/install-cygwin.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# install-cygwin.sh is the installation script for TSGL on Cygwin. +# Last updated: 07/14/2020 +# +# -SUBJECT TO CHANGE- +################################################################ + +echo "Installing TSGL..." + +echo + +#Clean install = remove the TSGL folder and lib files if they already exist +rm -rf /usr/local/include/TSGL +rm -rf /usr/local/lib/libtsgl.* + +#Create the following directories (Since they aren't included in github but are needed) +mkdir -p lib bin + +#Make the library +make + +#Install it +make install + +#Take out the .cpp files from the TSGL library package folder +rm -rf /usr/local/include/TSGL/*.cpp + +#Done +echo "Installation complete! Execute the runtests bash script to verify that everything works!" + +echo + diff --git a/install-mac b/install-mac index 2472d2756..7de9eedcf 100755 --- a/install-mac +++ b/install-mac @@ -66,6 +66,10 @@ brew install freetype echo "Installing Doxygen..." brew install doxygen +#cxxopts +echo "Installing cxxopts..." +brew install cxxopts + #g++ gVers=$(g++ -v 2>&1) gVeres=$(g++ -v 2>&1 | grep "gcc version" | cut -f 3 -d ' ' | tr -d .) @@ -82,17 +86,21 @@ then fi -#Now check if we need to install gcc9 +#Now check if we need to install gcc10 if grep --quiet clang check.txt; then echo "Installing g++...this may take a while!" brew install gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/gcc-9 /usr/local/bin/gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 /usr/local/bin/g++ + sudo rm /usr/local/bin/gcc + sudo rm /usr/local/bin/g++ + sudo ln -s /usr/local/Cellar/gcc/10.2.0/bin/gcc-10 /usr/local/bin/gcc + sudo ln -s /usr/local/Cellar/gcc/10.2.0/bin/g++-10 /usr/local/bin/g++ else - echo "Installing g++...this may take a while!2" + echo "Installing g++...this may take a while!" brew install gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/gcc-9 /usr/local/bin/gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 /usr/local/bin/g++ + sudo rm /usr/local/bin/gcc + sudo rm /usr/local/bin/g++ + sudo ln -s /usr/local/Cellar/gcc/10.2.0/bin/gcc-10 /usr/local/bin/gcc + sudo ln -s /usr/local/Cellar/gcc/10.2.0/bin/g++-10 /usr/local/bin/g++ fi #Symlinks diff --git a/runexamples b/runexamples new file mode 100755 index 000000000..b241c989b --- /dev/null +++ b/runexamples @@ -0,0 +1,45 @@ +#!/bin/bash + +run () { + echo "" + tput setaf 2 + echo "Running $@" + tput sgr0 + echo "" + $@ +} + +export LD_LIBRARY_PATH=lib # Make sure we load the TSGL library +cd src/examples # CD into the examples directory +make # create example binaries +cd ../.. # CD back to main TSGL directory + +EXAMPLES_PATH=src/examples + +# RUN EXAMPLES +run ./$EXAMPLES_PATH/ArrayBubbleSort/testArrayBubbleSort +run ./$EXAMPLES_PATH/ArrayShakerSort/testArrayShakerSort +run ./$EXAMPLES_PATH/Ballroom/testBallroom +run ./$EXAMPLES_PATH/Clock/testClock +run ./$EXAMPLES_PATH/Conway/testConway +run ./$EXAMPLES_PATH/CubeRun/testCubeRun +run ./$EXAMPLES_PATH/DiningPhilosophers/testPhilosophers +run ./$EXAMPLES_PATH/DiningPhilosophers3D/test3DPhilosophers +run ./$EXAMPLES_PATH/Fireworks/testFireworks +run ./$EXAMPLES_PATH/ForestFire/testForestFire +run ./$EXAMPLES_PATH/Langton/testLangton +run ./$EXAMPLES_PATH/Mandelbrot/testMandelbrot +run ./$EXAMPLES_PATH/MergeSort/testMergeSort +run ./$EXAMPLES_PATH/NewtonPendulum/testNewtonPendulum 900 400 11 # Width, Height, Number Of Balls +run ./$EXAMPLES_PATH/Pandemic/testPandemic +run ./$EXAMPLES_PATH/Pong/testPong +run ./$EXAMPLES_PATH/ProducerConsumer/testProducerConsumer +run ./$EXAMPLES_PATH/ReaderWriter/testReaderWriter +run ./$EXAMPLES_PATH/SeaUrchin/testSeaUrchin 16 # Threads +run ./$EXAMPLES_PATH/ShakerSort/testShakerSort +run ./$EXAMPLES_PATH/SolarSystem/testSolarSystem +run ./$EXAMPLES_PATH/ThreadedArrayAddition/testThreadedArrayAddition +run ./$EXAMPLES_PATH/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort +run ./$EXAMPLES_PATH/ThreadedArrayOperations/testThreadedArrayOperations +run ./$EXAMPLES_PATH/ThreadedSolarSystem/testThreadedSolarSystem +run ./$EXAMPLES_PATH/Voronoi/testVoronoi \ No newline at end of file diff --git a/runtests b/runtests index a184fc40f..703721b84 100755 --- a/runtests +++ b/runtests @@ -1,57 +1,73 @@ #!/bin/bash +# Note: tests must be run from the main TSGL directory, otherwise fonts and images won't load. + run () { - echo "$@" + echo "" + tput setaf 2 + echo "Running $@" + tput sgr0 + echo "" $@ } -export LD_LIBRARY_PATH=../lib #Make sure we load the TSGL library -cd bin #CD into our binary directory +TESTS_PATH=src/tests +export LD_LIBRARY_PATH=../lib # Make sure we load the TSGL library +cd src/tests && make # CD into test directory and call test Makefile +cd ../.. # CD back to main TSGL directory -run ./testAlphaRectangle 640 480 #Width, Height -run ./testArrows -run ./testAura 1200 900 8 #Width, Height, Segments -run ./testBallroom 640 640 #Width, Height -run ./testBlurImage 36 ../assets/pics/HDR_landscape.jpg #Threads, Image -run ./testCalcPi 100 4 #Segments, Threads -run ./testColorPoints 1000 1000 4 #Width, Height, Threads -run ./testColorWheel 640 640 64 #Width, Height, Threads -run ./testConcavePolygon #Width, Height -run ./testConstructors -run ./testConway 640 640 #Width, Height -run ./testCosineIntegral 640 480 32 #Width, Height, Threads -run ./testDumbSort 1200 600 #Width, Height -run ./testFireworks 800 800 4 50 10 #Width, Height, Threads, Fireworks, Speed -run ./testForestFire 800 600 #Width, Height -run ./testFunction 640 480 #Width, Height -run ./testGetPixels 4 #Threads -run ./testGradientWheel 640 640 256 #Width, Height, Threads -run ./testGraydient 400 400 8 #Width, Height, Threads -run ./testGreyscale 640 480 8 #Width, Height, Threads -run ./testHighData 1200 900 4 #Width, Height, Threads -run ./testImage 1200 600 #Width, Height -run ./testImageCart 1200 600 #Width, Height -run ./testInverter 8 #Threads -run ./testLangton 640 640 #Width, Height -run ./testLineChain 400 400 8 #Width, Height, Threads -run ./testLineFan 800 800 16 #Width, Height, Threads -run ./testMandelbrot 1200 900 8 255 #Width, Height, Threads, Depth -run ./testMouse 900 900 5 #Width, Height, Threads -run ./testNewtonPendulum 900 400 11 #Width, Height, Number Of Balls -run ./testPhilosophers 5 10 #Philosophers, Speed -run ./testPong 7 4 #Ball Speed, Paddle Speed -run ./testProducerConsumer 5 5 #Producers, Consumers -run ./testProgressBar 7 #Threads -run ./testProjectiles 400 400 #Width, Height -run ./testReaderWriter 6 6 #Readers, Writers, Priority, Starved -run ./testRotation 800 800 #Width, Height -run ./testSeaUrchin 16 #Threads -run ./testScreenshot 900 650 #Width, Height -run ./testSmartSort 1024 #Elements, Threads -run ./testSpectrogram ../assets/pics/test.png #Image -run ./testSpectrum 8 #Threads -run ./testStar -run ./testText 1200 900 ../assets/freefont/FreeSerif.ttf #Width, Height, Font -run ./testTextCart 1200 900 ../assets/freefont/FreeSerifItalic.ttf #Width, Height, Font -run ./testTextTwo 1200 900 #Width, Height -run ./testVoronoi 640 480 8 #Width, Height, Threads +# RUN TESTS +# run ./$TESTS_PATH/test_specs/test_specs +run ./$TESTS_PATH/test2Dvs3D/test2Dvs3D +run ./$TESTS_PATH/test3DRotation/test3DRotation +run ./$TESTS_PATH/testAlphaRectangle/testAlphaRectangle +run ./$TESTS_PATH/testArrows/testArrows +run ./$TESTS_PATH/testAura/testAura +run ./$TESTS_PATH/testBackground/testBackground +run ./$TESTS_PATH/testBlurImage/testBlurImage +run ./$TESTS_PATH/testCalcPi/testCalcPi 100 4 +run ./$TESTS_PATH/testCamera/testCamera +run ./$TESTS_PATH/testCircle/testCircle +run ./$TESTS_PATH/testColorWheel/testColorWheel +run ./$TESTS_PATH/testConcavePolygon/testConcavePolygon +run ./$TESTS_PATH/testCone/testCone +run ./$TESTS_PATH/testConvexPolygon/testConvexPolygon +run ./$TESTS_PATH/testCube/testCube +run ./$TESTS_PATH/testCuboid/testCuboid +run ./$TESTS_PATH/testCylinder/testCylinder +# run ./$TESTS_PATH/testDice/testDice +run ./$TESTS_PATH/testDiorama/testDiorama +run ./$TESTS_PATH/testEllipse/testEllipse +run ./$TESTS_PATH/testEllipsoid/testEllipsoid +run ./$TESTS_PATH/testGetPixels/testGetPixels +run ./$TESTS_PATH/testGradientWheel/testGradientWheel +run ./$TESTS_PATH/testGraydient/testGraydient +run ./$TESTS_PATH/testGreyscale/testGreyscale +run ./$TESTS_PATH/testHighData/testHighData +run ./$TESTS_PATH/testImage/testImage +run ./$TESTS_PATH/testImageCart/testImageCart +run ./$TESTS_PATH/testInverter/testInverter +run ./$TESTS_PATH/testLineChain/testLineChain +run ./$TESTS_PATH/testLineFan/testLineFan +run ./$TESTS_PATH/testLines/testLines +run ./$TESTS_PATH/testMouse/testMouse +run ./$TESTS_PATH/testPixels/testPixels +run ./$TESTS_PATH/testPrism/testPrism +run ./$TESTS_PATH/testProcedural/testProcedural +run ./$TESTS_PATH/testProgressBar/testProgressBar +run ./$TESTS_PATH/testProjectiles/testProjectiles +run ./$TESTS_PATH/testPyramid/testPyramid +run ./$TESTS_PATH/testRectangle/testRectangle +run ./$TESTS_PATH/testRegularPolygon/testRegularPolygon +run ./$TESTS_PATH/testScreenshot/testScreenshot +run ./$TESTS_PATH/testSpectrogram/testSpectrogram +run ./$TESTS_PATH/testSpectrum/testSpectrum +run ./$TESTS_PATH/testSphere/testSphere +run ./$TESTS_PATH/testSquare/testSquare +run ./$TESTS_PATH/testStar/testStar +run ./$TESTS_PATH/testText/testText +run ./$TESTS_PATH/testTextCart/testTextCart +run ./$TESTS_PATH/testTextTwo/testTextTwo +run ./$TESTS_PATH/testTransparency/testTransparency +run ./$TESTS_PATH/testTriangle/testTriangle +run ./$TESTS_PATH/testTriangleStrip/testTriangleStrip diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index b7fdfd6e7..5e8d3deb7 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -2,121 +2,668 @@ namespace tsgl { - /*! - * \brief Explicitly constructs a new monocolored Line. - * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color The reference variable to the color of the Line. - * \return A new Line with the specified endpoints and color. - */ - Arrow::Arrow(int x1, int y1, int x2, int y2, const ColorFloat color, bool doubleArrow) : ConcavePolygon((doubleArrow)? 10 : 7) { - headX = x2; headY = y2; - tailX = x1; tailY = y1; +/*!\brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x1 The x coordinate of the first endpoint of the arrow. + * \param y1 The y coordinate of the first endpoint of the arrow. + * \param z1 The z coordinate of the first endpoint of the arrow. + * \param x2 The x coordinate of the second endpoint of the arrow. + * \param y2 The y coordinate of the second endpoint of the arrow. + * \param z2 The z coordinate of the second endpoint of the arrow. + * \param width The width of the arrow at its widest points. + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color A ColorFloat for the color of the Arrow. + * \return A new Arrow with the specified endpoints and color. + */ +Arrow::Arrow(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow) : ConcavePolygon((x1 + x2) / 2, (y1 + y2) / 2, (z1 + z2) / 2, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + attribMutex.lock(); + myEndpointX1 = x1; myEndpointY1 = y1; myEndpointZ1 = z1; + myEndpointX2 = x2; myEndpointY2 = y2; myEndpointZ2 = z2; + myWidth = width; + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + isDoubleArrow = doubleArrow; + isOutlined = false; + + // general gist of this overly complicated vertex-adding process (thanks, 3D): + // 1. get the vector between the two endpoints (v1) + // 2. get the z-axis in a vector (v2) + // 3. get the normalized cross product of v1 and v2 (perpendicular to both) then scale it by width + // 4. get vectors containing the endpoints shifted to be centered around zero (e1 and e2) + // 5. get vectors containing the zero-centered endpoints shifted 10% closer to each other (base1 and base2) + // 6. Finally, add vertices based on the cross product and base1 and base2 to get the pointy parts of the Arrow + glm::vec3 v1 = { myEndpointX2 - myEndpointX1, myEndpointY2 - myEndpointY1, myEndpointZ2 - myEndpointZ1 }; + glm::vec3 v2 = { 0,0,1 }; + glm::vec3 cross = glm::normalize(glm::cross(v1, v2)); + cross *= myWidth; + glm::vec3 e1 = { myEndpointX1 - myCenterX, myEndpointY1 - myCenterY, myEndpointZ1 - myCenterZ }; + glm::vec3 e2 = { myEndpointX2 - myCenterX, myEndpointY2 - myCenterY, myEndpointZ2 - myCenterZ }; + + glm::vec3 base1 = { e1.x + v1.x / 10, e1.y + v1.y / 10, e1.z + v1.z / 10 }; + glm::vec3 base2 = { e2.x - v1.x / 10, e2.y - v1.y / 10, e2.z - v1.z / 10 }; + + attribMutex.unlock(); + addVertex(base1.x + cross.x * 0.2, base1.y + cross.y * 0.2, base1.z + cross.z * 0.2, color); + addVertex(base1.x + cross.x * 0.5, base1.y + cross.y * 0.5, base1.z + cross.z * 0.5, color); + addVertex(e1.x, e1.y, e1.z, color); + addVertex(base1.x + cross.x * -0.5, base1.y + cross.y * -0.5, base1.z + cross.z * -0.5, color); + addVertex(base1.x + cross.x * -0.2, base1.y + cross.y * -0.2, base1.z + cross.z * -0.2, color); + + addOutlineVertex(base1.x + cross.x * 0.2, base1.y + cross.y * 0.2, base1.z + cross.z * 0.2, GRAY); + addOutlineVertex(base1.x + cross.x * 0.5, base1.y + cross.y * 0.5, base1.z + cross.z * 0.5, GRAY); + addOutlineVertex(e1.x, e1.y, e1.z, GRAY); + addOutlineVertex(base1.x + cross.x * -0.5, base1.y + cross.y * -0.5, base1.z + cross.z * -0.5, GRAY); + addOutlineVertex(base1.x + cross.x * -0.2, base1.y + cross.y * -0.2, base1.z + cross.z * -0.2, GRAY); + + if( isDoubleArrow ) { + addVertex(base2.x + cross.x * -0.2, base2.y + cross.y * -0.2, base2.z + cross.z * -0.2, color); + addVertex(base2.x + cross.x * -0.5, base2.y + cross.y * -0.5, base2.z + cross.z * -0.5, color); + addVertex(e2.x, e2.y, e2.z, color); + addVertex(base2.x + cross.x * 0.5, base2.y + cross.y * 0.5, base2.z + cross.z * 0.5, color); + addVertex(base2.x + cross.x * 0.2, base2.y + cross.y * 0.2, base2.z + cross.z * 0.2, color); + + addOutlineVertex(base2.x + cross.x * -0.2, base2.y + cross.y * -0.2, base2.z + cross.z * -0.2, GRAY); + addOutlineVertex(base2.x + cross.x * -0.5, base2.y + cross.y * -0.5, base2.z + cross.z * -0.5, GRAY); + addOutlineVertex(e2.x, e2.y, e2.z, GRAY); + addOutlineVertex(base2.x + cross.x * 0.5, base2.y + cross.y * 0.5, base2.z + cross.z * 0.5, GRAY); + addOutlineVertex(base2.x + cross.x * 0.2, base2.y + cross.y * 0.2, base2.z + cross.z * 0.2, GRAY); + } else { + addVertex(e2.x + cross.x * -0.2, e2.y + cross.y * -0.2, e2.z + cross.z * -0.2, color); + addVertex(e2.x + cross.x * 0.2, e2.y + cross.y * 0.2, e2.z + cross.z * 0.2, color); + + addOutlineVertex(e2.x + cross.x * -0.2, e2.y + cross.y * -0.2, e2.z + cross.z * -0.2, GRAY); + addOutlineVertex(e2.x + cross.x * 0.2, e2.y + cross.y * 0.2, e2.z + cross.z * 0.2, GRAY); + } +} + +/*!\brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x1 The x coordinate of the first endpoint of the arrow. + * \param y1 The y coordinate of the first endpoint of the arrow. + * \param z1 The z coordinate of the first endpoint of the arrow. + * \param x2 The x coordinate of the second endpoint of the arrow. + * \param y2 The y coordinate of the second endpoint of the arrow. + * \param z2 The z coordinate of the second endpoint of the arrow. + * \param width The width of the arrow at its widest points. + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color An array of ColorFloats for the colors of the Arrow. + * \return A new Arrow with the specified endpoints and color. + */ +Arrow::Arrow(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow) : ConcavePolygon((x1 + x2) / 2, (y1 + y2) / 2, (z1 + z2) / 2, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + attribMutex.lock(); + myEndpointX1 = x1; myEndpointY1 = y1; myEndpointZ1 = z1; + myEndpointX2 = x2; myEndpointY2 = y2; myEndpointZ2 = z2; + myWidth = width; + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + isDoubleArrow = doubleArrow; + isOutlined = false; + + // general gist of this overly complicated vertex-adding process (thanks, 3D): + // 1. get the vector between the two endpoints (v1) + // 2. get the z-axis in a vector (v2) + // 3. get the normalized cross product of v1 and v2 (perpendicular to both) then scale it by width + // 4. get vectors containing the endpoints shifted to be centered around zero (e1 and e2) + // 5. get vectors containing the zero-centered endpoints shifted 10% closer to each other (base1 and base2) + // 6. Finally, add vertices based on the cross product and base1 and base2 to get the pointy parts of the Arrow + glm::vec3 v1 = { myEndpointX2 - myEndpointX1, myEndpointY2 - myEndpointY1, myEndpointZ2 - myEndpointZ1 }; + glm::vec3 v2 = { 0,0,1 }; + glm::vec3 cross = glm::normalize(glm::cross(v1, v2)); + cross *= myWidth; + glm::vec3 e1 = { myEndpointX1 - myCenterX, myEndpointY1 - myCenterY, myEndpointZ1 - myCenterZ }; + glm::vec3 e2 = { myEndpointX2 - myCenterX, myEndpointY2 - myCenterY, myEndpointZ2 - myCenterZ }; + + glm::vec3 base1 = { e1.x + v1.x / 10, e1.y + v1.y / 10, e1.z + v1.z / 10 }; + glm::vec3 base2 = { e2.x - v1.x / 10, e2.y - v1.y / 10, e2.z - v1.z / 10 }; + + attribMutex.unlock(); + addVertex(base1.x + cross.x * 0.2, base1.y + cross.y * 0.2, base1.z + cross.z * 0.2, color[0]); + addVertex(base1.x + cross.x * 0.5, base1.y + cross.y * 0.5, base1.z + cross.z * 0.5, color[0]); + addVertex(e1.x, e1.y, e1.z, color[0]); + addVertex(base1.x + cross.x * -0.5, base1.y + cross.y * -0.5, base1.z + cross.z * -0.5, color[0]); + addVertex(base1.x + cross.x * -0.2, base1.y + cross.y * -0.2, base1.z + cross.z * -0.2, color[0]); + + addOutlineVertex(base1.x + cross.x * 0.2, base1.y + cross.y * 0.2, base1.z + cross.z * 0.2, GRAY); + addOutlineVertex(base1.x + cross.x * 0.5, base1.y + cross.y * 0.5, base1.z + cross.z * 0.5, GRAY); + addOutlineVertex(e1.x, e1.y, e1.z, GRAY); + addOutlineVertex(base1.x + cross.x * -0.5, base1.y + cross.y * -0.5, base1.z + cross.z * -0.5, GRAY); + addOutlineVertex(base1.x + cross.x * -0.2, base1.y + cross.y * -0.2, base1.z + cross.z * -0.2, GRAY); + + if( isDoubleArrow ) { + addVertex(base2.x + cross.x * -0.2, base2.y + cross.y * -0.2, base2.z + cross.z * -0.2, color[1]); + addVertex(base2.x + cross.x * -0.5, base2.y + cross.y * -0.5, base2.z + cross.z * -0.5, color[1]); + addVertex(e2.x, e2.y, e2.z, color[1]); + addVertex(base2.x + cross.x * 0.5, base2.y + cross.y * 0.5, base2.z + cross.z * 0.5, color[1]); + addVertex(base2.x + cross.x * 0.2, base2.y + cross.y * 0.2, base2.z + cross.z * 0.2, color[1]); + + addOutlineVertex(base2.x + cross.x * -0.2, base2.y + cross.y * -0.2, base2.z + cross.z * -0.2, GRAY); + addOutlineVertex(base2.x + cross.x * -0.5, base2.y + cross.y * -0.5, base2.z + cross.z * -0.5, GRAY); + addOutlineVertex(e2.x, e2.y, e2.z, GRAY); + addOutlineVertex(base2.x + cross.x * 0.5, base2.y + cross.y * 0.5, base2.z + cross.z * 0.5, GRAY); + addOutlineVertex(base2.x + cross.x * 0.2, base2.y + cross.y * 0.2, base2.z + cross.z * 0.2, GRAY); + } else { + addVertex(e2.x + cross.x * -0.2, e2.y + cross.y * -0.2, e2.z + cross.z * -0.2, color[1]); + addVertex(e2.x + cross.x * 0.2, e2.y + cross.y * 0.2, e2.z + cross.z * 0.2, color[1]); + + addOutlineVertex(e2.x + cross.x * -0.2, e2.y + cross.y * -0.2, e2.z + cross.z * -0.2, GRAY); + addOutlineVertex(e2.x + cross.x * 0.2, e2.y + cross.y * 0.2, e2.z + cross.z * 0.2, GRAY); + } +} + +/*! + * \brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x The x coordinate of the center of the arrow. + * \param y The y coordinate of the center of the arrow. + * \param z The z coordinate of the center of the arrow. + * \param length The length of the arrow (from endpoint to endpoint). + * \param width The width of the arrow (between its widest points). + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color A ColorFloat for the color of the Arrow. + * \return A new Arrow with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. + */ +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + if (width <= 0 || length <= 0) { + TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); + return; + } + attribMutex.lock(); + myLength = length; + myWidth = width; isDoubleArrow = doubleArrow; - headColor = color; - tailColor = color; - generateVertices(); - } - - /*! - * \brief Explicitly constructs a new multicolored Line. - * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array of colors for the line endpoints. - * \return A new Line with the specified endpoints and endpoint colors. - */ - Arrow::Arrow(int x1, int y1, int x2, int y2, const ColorFloat color[], bool doubleArrow) : ConcavePolygon((doubleArrow)? 10 : 7) { - headX = x2; headY = y2; - tailX = x1; tailY = y1; + isOutlined = false; + myEndpointX1 = -myLength/2 + x; + myEndpointX2 = myLength/2 + x; + myEndpointY1 = myEndpointY2 = y; + myEndpointZ1 = myEndpointZ2 = z; + attribMutex.unlock(); + addVertex(-0.4 * myLength, 0.2 * myWidth, 0, color); + addVertex(-0.4 * myLength, 0.5 * myWidth, 0, color); + addVertex(-0.5 * myLength, 0, 0, color); + addVertex(-0.4 * myLength, -0.5 * myWidth, 0, color); + addVertex(-0.4 * myLength, -0.2 * myWidth, 0, color); + + addOutlineVertex(-0.4 * myLength, 0.2 * myWidth, 0, GRAY); + addOutlineVertex(-0.4 * myLength, 0.5 * myWidth, 0, GRAY); + addOutlineVertex(-0.5 * myLength, 0, 0, GRAY); + addOutlineVertex(-0.4 * myLength, -0.5 * myWidth, 0, GRAY); + addOutlineVertex(-0.4 * myLength, -0.2 * myWidth, 0, GRAY); + + if( isDoubleArrow ) { + addVertex(0.4 * myLength, -0.2 * myWidth, 0, color); + addVertex(0.4 * myLength, -0.5 * myWidth, 0, color); + addVertex(0.5 * myLength, 0, 0, color); + addVertex(0.4 * myLength, 0.5 * myWidth, 0, color); + addVertex(0.4 * myLength, 0.2 * myWidth, 0, color); + + addOutlineVertex(0.4 * myLength, -0.2 * myWidth, 0, GRAY); + addOutlineVertex(0.4 * myLength, -0.5 * myWidth, 0, GRAY); + addOutlineVertex(0.5 * myLength, 0, 0, GRAY); + addOutlineVertex(0.4 * myLength, 0.5 * myWidth, 0, GRAY); + addOutlineVertex(0.4 * myLength, 0.2 * myWidth, 0, GRAY); + } else { + addVertex(0.5 * myLength, -.2 * myWidth, 0, color); + addVertex(0.5 * myLength, .2 * myWidth, 0, color); + + addOutlineVertex(0.5 * myLength, -.2 * myWidth, 0, GRAY); + addOutlineVertex(0.5 * myLength, .2 * myWidth, 0, GRAY); + } +} + +/*! + * \brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x The x coordinate of the center of the arrow. + * \param y The y coordinate of the center of the arrow. + * \param z The z coordinate of the center of the arrow. + * \param length The length of the arrow (from endpoint to endpoint). + * \param width The width of the arrow (between its widest points). + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color An array of ColorFloats for the colors of the Arrow. + * \return A new Arrow with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. + */ +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + if (width <= 0 || length <= 0) { + TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); + return; + } + attribMutex.lock(); + myLength = length; + myWidth = width; isDoubleArrow = doubleArrow; - headColor = color[0]; - tailColor = color[1]; - generateVertices(); - } - - /*! - * \brief private method helping constructor initialize vertices array for monocolored arrow - */ - void Arrow::generateVertices() { - //TODO: figure out locking for this since we are adding vertices, which uses the lock - makeArrowHead(headX, headY, headX-tailX, headY-tailY, headColor); + isOutlined = false; + myEndpointX1 = -myLength/2 + x; + myEndpointX2 = myLength/2 + x; + myEndpointY1 = myEndpointY2 = y; + myEndpointZ1 = myEndpointZ2 = z; + attribMutex.unlock(); + addVertex(-0.4 * myLength, 0.2 * myWidth, 0, color[0]); + addVertex(-0.4 * myLength, 0.5 * myWidth, 0, color[0]); + addVertex(-0.5 * myLength, 0, 0, color[0]); + addVertex(-0.4 * myLength, -0.5 * myWidth, 0, color[0]); + addVertex(-0.4 * myLength, -0.2 * myWidth, 0, color[0]); + + addOutlineVertex(-0.4 * myLength, 0.2 * myWidth, 0, GRAY); + addOutlineVertex(-0.4 * myLength, 0.5 * myWidth, 0, GRAY); + addOutlineVertex(-0.5 * myLength, 0, 0, GRAY); + addOutlineVertex(-0.4 * myLength, -0.5 * myWidth, 0, GRAY); + addOutlineVertex(-0.4 * myLength, -0.2 * myWidth, 0, GRAY); + + if( isDoubleArrow ) { + addVertex(0.4 * myLength, -0.2 * myWidth, 0, color[1]); + addVertex(0.4 * myLength, -0.5 * myWidth, 0, color[1]); + addVertex(0.5 * myLength, 0, 0, color[1]); + addVertex(0.4 * myLength, 0.5 * myWidth, 0, color[1]); + addVertex(0.4 * myLength, 0.2 * myWidth, 0, color[1]); + + addOutlineVertex(0.4 * myLength, -0.2 * myWidth, 0, GRAY); + addOutlineVertex(0.4 * myLength, -0.5 * myWidth, 0, GRAY); + addOutlineVertex(0.5 * myLength, 0, 0, GRAY); + addOutlineVertex(0.4 * myLength, 0.5 * myWidth, 0, GRAY); + addOutlineVertex(0.4 * myLength, 0.2 * myWidth, 0, GRAY); + } else { + addVertex(0.5 * myLength, -0.2 * myWidth, 0, color[1]); + addVertex(0.5 * myLength, 0.2 * myWidth, 0, color[1]); + + addOutlineVertex(0.5 * myLength, -.2 * myWidth, 0, GRAY); + addOutlineVertex(0.5 * myLength, .2 * myWidth, 0, GRAY); + } + attribMutex.lock(); + myAlpha = (color[0].A + color[1].A) / 2; + attribMutex.unlock(); +} + +/*!\brief Replacement mutator for the length of the Arrow. + * \details Sets the value of the myLength instance variable to the parameter, and modifies the vertices array accordingly. + * \param length New length of the Arrow, a float. + */ +void Arrow::setLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have an Arrow with length less than or equal to 0."); + return; + } + attribMutex.lock(); + float ratio = length / myLength; + myLength = length; + myEndpointX1 = (myEndpointX1 - myCenterX) * ratio + myCenterX; + myEndpointY1 = (myEndpointY1 - myCenterY) * ratio + myCenterY; + myEndpointZ1 = (myEndpointZ1 - myCenterZ) * ratio + myCenterZ; + myEndpointX2 = (myEndpointX2 - myCenterX) * ratio + myCenterX; + myEndpointY2 = (myEndpointY2 - myCenterY) * ratio + myCenterY; + myEndpointZ2 = (myEndpointZ2 - myCenterZ) * ratio + myCenterZ; + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Alteration mutator for the length of the Arrow. + * \details Alters the value of the myLength instance variable by delta and modifies the vertices array accordingly. + * \param delta The difference between the old and new lengths of the Arrow. + */ +void Arrow::changeLengthBy(GLfloat delta) { + if (myLength + delta <= 0) { + TsglDebug("Cannot have an Arrow with length less than or equal to 0."); + return; + } + attribMutex.lock(); + float ratio = (myLength + delta) / myLength; + myLength += delta; + myEndpointX1 = (myEndpointX1 - myCenterX) * ratio + myCenterX; + myEndpointY1 = (myEndpointY1 - myCenterY) * ratio + myCenterY; + myEndpointZ1 = (myEndpointZ1 - myCenterZ) * ratio + myCenterZ; + myEndpointX2 = (myEndpointX2 - myCenterX) * ratio + myCenterX; + myEndpointY2 = (myEndpointY2 - myCenterY) * ratio + myCenterY; + myEndpointZ2 = (myEndpointZ2 - myCenterZ) * ratio + myCenterZ; + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Replacement mutator for the width of the Arrow. + * \details Sets the value of the myWidth instance variable to the parameter, and modifies the vertices array accordingly. + * \param width New width of the Arrow, a float. + */ +void Arrow::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have an Arrow with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = width; + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Alteration mutator for the width of the Arrow. + * \details Alters the value of the myWidth instance variable by delta and modifies the vertices array accordingly. + * \param delta The difference between the old and new widths of the Arrow. + */ +void Arrow::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have an Arrow with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth += delta; + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Mutator for the first endpoint coordinates of the Arrow. + * \details Sets the values of myEndpoint_1 instance variables by the parameters and modifies the vertices array accordingly. + * \param x The new x-coordinate of the first endpoint of the Arrow. + * \param y The new y-coordinate of the first endpoint of the Arrow. + * \param z The new z-coordinate of the first endpoint of the Arrow. + */ +void Arrow::setFirstEndpoint(GLfloat x, GLfloat y, GLfloat z) { + attribMutex.lock(); + myEndpointX1 = x; myEndpointY1 = y; myEndpointZ1 = z; + if (centerMatchesRotationPoint()) { + myRotationPointX = (myEndpointX2 + myEndpointX1) / 2; + myRotationPointY = (myEndpointY2 + myEndpointY1) / 2; + myRotationPointZ = (myEndpointZ2 + myEndpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (myEndpointX2 + myEndpointX1) / 2; + myCenterY = (myEndpointY2 + myEndpointY1) / 2; + myCenterZ = (myEndpointZ2 + myEndpointZ1) / 2; + } + myCurrentYaw = myCurrentPitch = myCurrentRoll = 0; + myLength = sqrt(pow(myEndpointX2 - myEndpointX1, 2) + pow(myEndpointY2 - myEndpointY1, 2) + pow(myEndpointZ2 - myEndpointZ1, 2)); + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Mutator for the second endpoint coordinates of the Arrow. + * \details Sets the values of myEndpoint_2 instance variables by the parameters and modifies the vertices array accordingly. + * \param x The new x-coordinate of the second endpoint of the Arrow. + * \param y The new y-coordinate of the second endpoint of the Arrow. + * \param z The new z-coordinate of the second endpoint of the Arrow. + */ +void Arrow::setSecondEndpoint(GLfloat x, GLfloat y, GLfloat z) { + attribMutex.lock(); + myEndpointX2 = x; myEndpointY2 = y; myEndpointZ2 = z; + if (centerMatchesRotationPoint()) { + myRotationPointX = (myEndpointX2 + myEndpointX1) / 2; + myRotationPointY = (myEndpointY2 + myEndpointY1) / 2; + myRotationPointZ = (myEndpointZ2 + myEndpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (myEndpointX2 + myEndpointX1) / 2; + myCenterY = (myEndpointY2 + myEndpointY1) / 2; + myCenterZ = (myEndpointZ2 + myEndpointZ1) / 2; + } + myCurrentYaw = myCurrentPitch = myCurrentRoll = 0; + myLength = sqrt(pow(myEndpointX2 - myEndpointX1, 2) + pow(myEndpointY2 - myEndpointY1, 2) + pow(myEndpointZ2 - myEndpointZ1, 2)); + attribMutex.unlock(); + recalculateVertices(); +} + +/*!\brief Accessor for the x-coordinate of the Arrow's first endpoint. + * \details Returns the value of the myEndpointX1 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointX1, containing the value of the Arrow's first endpoint's x-coordinate. + * \note See Drawable::getCenterX() documentation for more info. + */ +float Arrow::getFirstEndpointX() { + attribMutex.lock(); + float ex1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ex1 = myEndpointX1; + attribMutex.unlock(); + return ex1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ex1 = myEndpointX1; + attribMutex.unlock(); + return ex1; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ex1 = cosYaw * cosPitch * (myEndpointX1 - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myEndpointY1 - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myEndpointZ1 - myRotationPointZ) + myRotationPointX; + attribMutex.unlock(); + return ex1; +} + +/*!\brief Accessor for the y-coordinate of the Arrow's first endpoint. + * \details Returns the value of the myEndpointY1 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointY1, containing the value of the Arrow's first endpoint's y-coordinate. + * \note See Drawable::getCenterY() documentation for more info. + */ +float Arrow::getFirstEndpointY() { + attribMutex.lock(); + float ey1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ey1 = myEndpointY1; + attribMutex.unlock(); + return ey1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ey1 = myEndpointY1; + attribMutex.unlock(); + return ey1; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ey1 = sinYaw * cosPitch * (myEndpointX1 - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myEndpointY1 - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myEndpointZ1 - myRotationPointZ) + myRotationPointY; + attribMutex.unlock(); + return ey1; +} + +/*!\brief Accessor for the z-coordinate of the Arrow's first endpoint. + * \details Returns the value of the myEndpointZ1 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointZ1, containing the value of the Arrow's first endpoint's z-coordinate. + * \note See Drawable::getCenterZ() documentation for more info. + */ +float Arrow::getFirstEndpointZ() { + attribMutex.lock(); + float ez1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ez1 = myEndpointZ1; + attribMutex.unlock(); + return ez1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ez1 = myEndpointZ1; + attribMutex.unlock(); + return ez1; + } + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ez1 = -sinPitch * (myEndpointX1 - myRotationPointX) + cosPitch * sinRoll * (myEndpointY1 - myRotationPointY) + cosPitch * cosRoll * (myEndpointZ1 - myRotationPointZ) + myRotationPointZ; + attribMutex.unlock(); + return ez1; +} + +/*!\brief Accessor for the x-coordinate of the Arrow's second endpoint. + * \details Returns the value of the myEndpointX2 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointX2, containing the value of the Arrow's second endpoint's x-coordinate. + * \note See Drawable::getCenterX() documentation for more info. + */ +float Arrow::getSecondEndpointX() { + attribMutex.lock(); + float ex2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ex2 = myEndpointX2; + attribMutex.unlock(); + return ex2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ex2 = myEndpointX2; + attribMutex.unlock(); + return ex2; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ex2 = cosYaw * cosPitch * (myEndpointX2 - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myEndpointY2 - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myEndpointZ2 - myRotationPointZ) + myRotationPointX; + attribMutex.unlock(); + return ex2; +} + +/*!\brief Accessor for the y-coordinate of the Arrow's second endpoint. + * \details Returns the value of the myEndpointY2 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointY2, containing the value of the Arrow's second endpoint's y-coordinate. + * \note See Drawable::getCenterY() documentation for more info. + */ +float Arrow::getSecondEndpointY() { + attribMutex.lock(); + float ey2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ey2 = myEndpointY2; + attribMutex.unlock(); + return ey2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ey2 = myEndpointY2; + attribMutex.unlock(); + return ey2; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ey2 = sinYaw * cosPitch * (myEndpointX2 - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myEndpointY2 - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myEndpointZ2 - myRotationPointZ) + myRotationPointY; + attribMutex.unlock(); + return ey2; +} + +/*!\brief Accessor for the z-coordinate of the Arrow's second endpoint. + * \details Returns the value of the myEndpointZ2 instance variable, rotated around myRotationPoint by myCurrentYawPitchRoll. + * \return myEndpointZ2, containing the value of the Arrow's second endpoint's z-coordinate. + * \note See Drawable::getCenterZ() documentation for more info. + */ +float Arrow::getSecondEndpointZ() { + attribMutex.lock(); + float ez2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ez2 = myEndpointZ2; + attribMutex.unlock(); + return ez2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ez2 = myEndpointZ2; + attribMutex.unlock(); + return ez2; + } + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ez2 = -sinPitch * (myEndpointX2 - myRotationPointX) + cosPitch * sinRoll * (myEndpointY2 - myRotationPointY) + cosPitch * cosRoll * (myEndpointZ2 - myRotationPointZ) + myRotationPointZ; + attribMutex.unlock(); + return ez2; +} + +/** + * \brief Sets the Arrow to a new color. + * \param c The new array of ColorFloats. + * \note Overrides Shape::setColor(ColorFloat c[]). + */ +void Arrow::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = (c[0].A + c[1].A) / 2; + for(int i = 0; i < 7; i++) { + vertices[i*7 + 3] = c[i/5].R; + vertices[i*7 + 4] = c[i/5].G; + vertices[i*7 + 5] = c[i/5].B; + vertices[i*7 + 6] = c[i/5].A; + } + if (isDoubleArrow) { + for(int i = 7; i < 10; i++) { + vertices[i*7 + 3] = c[1].R; + vertices[i*7 + 4] = c[1].G; + vertices[i*7 + 5] = c[1].B; + vertices[i*7 + 6] = c[1].A; + } + } + attribMutex.unlock(); +} + +/** + * \brief Accessor for Arrow's colors. + * \details Populates the reference parameter vector with a ColorFloat for each end of Arrow. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Arrow will be pushed. + * \note Overrides Shape::getColors(). + */ +void Arrow::getColors(std::vector &colorVec) { + attribMutex.lock(); + colorVec.push_back(ColorFloat(vertices[3],vertices[4],vertices[5],vertices[6])); + colorVec.push_back(ColorFloat(vertices[38],vertices[39],vertices[40],vertices[41])); + attribMutex.unlock(); +} + +/*! \brief Private helper method that recalculates vertices array whenever endpoints are altered. + * \details Assigns new values to coordinates section of vertices[], principally based on myEndpoint and myWidth. + */ +void Arrow::recalculateVertices() { + attribMutex.lock(); + glm::vec3 v1 = { myEndpointX2 - myEndpointX1, myEndpointY2 - myEndpointY1, myEndpointZ2 - myEndpointZ1 }; + glm::vec3 v2 = { 0,0,1 }; + glm::vec3 cross = glm::normalize(glm::cross(v1, v2)); + cross *= myWidth; + glm::vec3 e1 = { myEndpointX1 - myCenterX, myEndpointY1 - myCenterY, myEndpointZ1 - myCenterZ }; + glm::vec3 e2 = { myEndpointX2 - myCenterX, myEndpointY2 - myCenterY, myEndpointZ2 - myCenterZ }; + + glm::vec3 base1 = { e1.x + v1.x / 10, e1.y + v1.y / 10, e1.z + v1.z / 10 }; + glm::vec3 base2 = { e2.x - v1.x / 10, e2.y - v1.y / 10, e2.z - v1.z / 10 }; + + vertices[0] = base1.x + cross.x * 0.2; vertices[1] = base1.y + cross.y * 0.2; vertices[2] = base1.z + cross.z * 0.2; + vertices[7] = base1.x + cross.x * 0.5; vertices[8] = base1.y + cross.y * 0.5; vertices[9] = base1.z + cross.z * 0.5; + vertices[14] = e1.x; vertices[15] = e1.y; vertices[16] = e1.z; + vertices[21] = base1.x + cross.x * -0.5; vertices[22] = base1.y + cross.y * -0.5; vertices[23] = base1.z + cross.z * -0.5; + vertices[28] = base1.x + cross.x * -0.2; vertices[29] = base1.y + cross.y * -0.2; vertices[30] = base1.z + cross.z * -0.2; + + outlineVertices[0] = base1.x + cross.x * 0.2; outlineVertices[1] = base1.y + cross.y * 0.2; outlineVertices[2] = base1.z + cross.z * 0.2; + outlineVertices[7] = base1.x + cross.x * 0.5; outlineVertices[8] = base1.y + cross.y * 0.5; outlineVertices[9] = base1.z + cross.z * 0.5; + outlineVertices[14] = e1.x; outlineVertices[15] = e1.y; outlineVertices[16] = e1.z; + outlineVertices[21] = base1.x + cross.x * -0.5; outlineVertices[22] = base1.y + cross.y * -0.5; outlineVertices[23] = base1.z + cross.z * -0.5; + outlineVertices[28] = base1.x + cross.x * -0.2; outlineVertices[29] = base1.y + cross.y * -0.2; outlineVertices[30] = base1.z + cross.z * -0.2; if( isDoubleArrow ) { - makeArrowHead(tailX, tailY, tailX-headX, tailY-headY, tailColor); + vertices[35] = base2.x + cross.x * -0.2; vertices[36] = base2.y + cross.y * -0.2; vertices[37] = base2.z + cross.z * -0.2; + vertices[42] = base2.x + cross.x * -0.5; vertices[43] = base2.y + cross.y * -0.5; vertices[44] = base2.z + cross.z * -0.5; + vertices[49] = e2.x; vertices[50] = e2.y; vertices[51] = e2.z; + vertices[56] = base2.x + cross.x * 0.5; vertices[57] = base2.y + cross.y * 0.5; vertices[58] = base2.z + cross.z * 0.5; + vertices[63] = base2.x + cross.x * 0.2; vertices[64] = base2.y + cross.y * 0.2; vertices[65] = base2.z + cross.z * 0.2; + + outlineVertices[35] = base2.x + cross.x * -0.2; outlineVertices[36] = base2.y + cross.y * -0.2; outlineVertices[37] = base2.z + cross.z * -0.2; + outlineVertices[42] = base2.x + cross.x * -0.5; outlineVertices[43] = base2.y + cross.y * -0.5; outlineVertices[44] = base2.z + cross.z * -0.5; + outlineVertices[49] = e2.x; outlineVertices[50] = e2.y; outlineVertices[51] = e2.z; + outlineVertices[56] = base2.x + cross.x * 0.5; outlineVertices[57] = base2.y + cross.y * 0.5; outlineVertices[58] = base2.z + cross.z * 0.5; + outlineVertices[63] = base2.x + cross.x * 0.2; outlineVertices[64] = base2.y + cross.y * 0.2; outlineVertices[65] = base2.z + cross.z * 0.2; } else { - int a, b; //Offsets for vertices - if( tailY < headY ) a = 1; - else a = -1; - if( tailX > headX ) b = 1; - else b = -1; - - addVertex(tailX-a, tailY-b, tailColor); - addVertex(tailX+a, tailY+b, tailColor); - } - } - - /** - * \brief Moves the head of the Arrow. - * \details Changes the coordinates of the first point in the Arrow to a new x and y. - * \param x The new x coordinate of the head. - * \param y The new y coordinate of the head. - */ - void Arrow::moveHead(float x, float y) { - attribMutex.lock(); - current = 0; init = false; - headX = x; headY = y; - attribMutex.unlock(); - generateVertices(); - } - - /** - * \brief Moves the tail of the Arrow. - * \details Changes the coordinates of the second point in the Arrow to a new x and y. - * \param x The new x coordinate of the tail. - * \param y The new y coordinate of the tail. - */ - void Arrow::moveTail(float x, float y) { - attribMutex.lock(); - current = 0; init = false; - tailX = x; tailY = y; - attribMutex.unlock(); - generateVertices(); - } - - /*! - * \brief private method helping constructor for the arrow heads - */ - void Arrow::makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorFloat color) { - - int a, b; - if( deltaY > 0 ) a = 1; - else a = -1; - if( deltaX < 0 ) b = 1; - else b = -1; - - float angle = atan( deltaY / deltaX ); - float s = sin( angle ), c = cos( angle ); - float x1 = -10*c-(-5)*s, x2 = 2*c - 0*s, x3 = -10*c-5*s; - float y1 = -10*s+(-5)*c, y2 = 2*s + 0*c, y3 = -10*s+5*c; - // if we have an arrow pointing left, rotate it pi radians ( sin = 0, cos = -1) - if (deltaX < 0) { - x1 = -x1, x2 = -x2, x3 = -x3; - y1 = -y1, y2 = -y2, y3 = -y3; - } - // transpose the triangle to the end of the line - x1 += x, x2 += x, x3 += x; - y1 += y, y2 += y, y3 += y; - - addVertex( (x1+x3)/2+a, (y1+y3)/2+b, color ); - addVertex(x1, y1, color); - addVertex(x2, y2, color); - addVertex(x3, y3, color); - addVertex( (x1+x3)/2-a, (y1+y3)/2-b, color ); - } + vertices[35] = e2.x + cross.x * -0.2; vertices[36] = e2.y + cross.y * -0.2; vertices[37] = e2.z + cross.z * -0.2; + vertices[42] = e2.x + cross.x * 0.2; vertices[43] = e2.y + cross.y * 0.2; vertices[44] = e2.z + cross.z * 0.2; + + outlineVertices[35] = e2.x + cross.x * -0.2; outlineVertices[36] = e2.y + cross.y * -0.2; outlineVertices[37] = e2.z + cross.z * -0.2; + outlineVertices[42] = e2.x + cross.x * 0.2; outlineVertices[43] = e2.y + cross.y * 0.2; outlineVertices[44] = e2.z + cross.z * 0.2; + } + attribMutex.unlock(); +} + } \ No newline at end of file diff --git a/src/TSGL/Arrow.h b/src/TSGL/Arrow.h index a89f39c3c..b2d9becfe 100644 --- a/src/TSGL/Arrow.h +++ b/src/TSGL/Arrow.h @@ -1,35 +1,75 @@ /* - * Arrow.h extends Shape and provides a class for drawing a single line to a Canvas. + * Arrow.h extends ConcavePolygon and provides a class for drawing an Arrow shape to a Canvas. */ #ifndef ARROW_H_ #define ARROW_H_ -#include "ConcavePolygon.h" // For extending our Shape object +#include "ConcavePolygon.h" // For extending our ConcavePolygon object namespace tsgl { /*! \class Arrow * \brief Draw a simple Arrow. - * \details Line is a class for holding vertex data for a simple Arrow. + * \details Arrow is a class for holding vertex data for a concave polygon shaped like an Arrow. */ class Arrow : public ConcavePolygon { private: - int headX, headY, tailX, tailY; bool isDoubleArrow; - ColorFloat headColor; - ColorFloat tailColor; - void makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorFloat color); // Helps constructor by calculating the Arrow Head's coordinates - void generateVertices(); + GLfloat myLength, myWidth; + GLfloat myEndpointX1, myEndpointY1, myEndpointZ1, myEndpointX2, myEndpointY2, myEndpointZ2; + + void recalculateVertices(); public: + Arrow(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false); - Arrow(int x1, int y1, int x2, int y2, const ColorFloat color, bool doubleArrow = false); + Arrow(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false); - Arrow(int x1, int y1, int x2, int y2, const ColorFloat color[], bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false); - void moveHead(float x, float y); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false); - void moveTail(float x, float y); + void setLength(GLfloat length); + + void changeLengthBy(GLfloat delta); + + /*!\brief Accessor for the length of the arrow from endpoint to endpoint. + * \details Returns the value of the myLength instance variable. + * \return myLength, containing the distance in 3D space between the two endpoints. + */ + GLfloat getLength() { return myLength; } + + void setWidth(GLfloat width); + + void changeWidthBy(GLfloat delta); + + /*!\brief Accessor for the width of the arrow from widest point to widest point. + * \details Returns the value of the myLength instance variable. + * \return myLength, containing the distance in 3D space between the two endpoints. + */ + GLfloat getWidth() { return myWidth; } + + void setFirstEndpoint(GLfloat x, GLfloat y, GLfloat z); + + void setSecondEndpoint(GLfloat x, GLfloat y, GLfloat z); + + GLfloat getFirstEndpointX(); + + GLfloat getFirstEndpointY(); + + GLfloat getFirstEndpointZ(); + + GLfloat getSecondEndpointX(); + + GLfloat getSecondEndpointY(); + + GLfloat getSecondEndpointZ(); + + virtual void setColor(ColorFloat c) { Shape::setColor(c); } + + virtual void setColor(ColorFloat c[]); + + virtual void getColors(std::vector &colorVec); }; } diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp new file mode 100644 index 000000000..8369edcc6 --- /dev/null +++ b/src/TSGL/Background.cpp @@ -0,0 +1,1028 @@ +#include "Background.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Background. + * \details Explicit constructor for a Background object. + * \param width Background's width in pixels. + * \param height Background's height in pixels. + * \param c A ColorFloat for the Background's original color. + * \warning An invariant is held where if width or height isn't positive then an error message is given. + * \return A new Background to which Drawables and Pixels can be drawn procedurally. + */ +Background::Background(GLint width, GLint height, const ColorFloat &clearColor) { + if (width <= 0 || height <= 0) { + TsglDebug("Cannot have a Background with non-positive width or height."); + } + attribMutex.lock(); + myWidth = width; + myHeight = height; + myDrawables = new Array(myWidth * myHeight * 2); + baseColor = clearColor; + toClear = false; + complete = false; + newPixelsDrawn = true; + + pixelTextureBuffer = new uint8_t[myWidth * myHeight * 4]; + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + pixelBufferMutex.unlock(); + + myWorldZ = 4000; + vertices = new GLfloat[30]; + vertices[0] = vertices[11] = vertices[21] = vertices[10] = vertices[26] = vertices[20] = -0.5 * ((myHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myHeight / 2) / tan(glm::pi()/6)); // x + y + vertices[5] = vertices[1] = vertices[15] = vertices[6] = vertices[25] = vertices[16] = 0.5 * ((myHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myHeight / 2) / tan(glm::pi()/6)); // x + y + vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = -myWorldZ; // z + vertices[3] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[29] = 0.0; // texture coord x + y + vertices[4] = vertices[8] = vertices[9] = vertices[18] = vertices[19] = vertices[28] = 1.0; // texture coord x + y + attribMutex.unlock(); +} + +/*! \brief Assigns Drawable shaders and initializes framebuffers within the parameter window's context. + * \details Assigns shapeShader, textShader, textureShader to parameters and initializes two framebuffers: MSAA and non-MSAA. + * \param shapeS Pointer to a shader for Shape Drawables. + * \param textS Pointer to a shader for Text Drawables. + * \param textureS Pointer to a shader for texture rendering. + * \param window GLFWwindow * within whose context the framebuffers will be initialized. + */ +void Background::init(Shader * shapeS, Shader * textS, Shader * textureS, Camera * camera, GLFWwindow * window) { + attribMutex.lock(); + glfwMakeContextCurrent(window); + glfwGetFramebufferSize(window, &framebufferWidth, &framebufferHeight); + + readPixelMutex.lock(); + readPixelBuffer = new uint8_t[myWidth * myHeight * 3]; + for (int i = 0; i < myWidth * myHeight * 3; ++i) { + readPixelBuffer[i] = 0; + } + readPixelMutex.unlock(); + // configure MSAA framebuffer + // -------------------------- + glGenFramebuffers(1, &multisampledFBO); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + // create a multisampled color attachment texture + glGenTextures(1, &multisampledTexture); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, myWidth, myHeight, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); + // create multisampled renderbuffer object + glGenRenderbuffers(1, &RBO); + glBindRenderbuffer(GL_RENDERBUFFER, RBO); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Create a second framebuffer, non-MSAA + // -------------------------- + intermediateFBO = 0; + glGenFramebuffers(1, &intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + glGenTextures(1, &intermediateTexture); + glBindTexture(GL_TEXTURE_2D, intermediateTexture); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, myWidth, myHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,intermediateTexture, 0); + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glClear(GL_COLOR_BUFFER_BIT); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // generate a texture for the pixels + // -------------------------- + glGenTextures(1, &pixelTexture); + glBindTexture(GL_TEXTURE_2D, pixelTexture); + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + + shapeShader = shapeS; + textShader = textS; + textureShader = textureS; + myCamera = camera; + complete = true; + glfwMakeContextCurrent(0); + attribMutex.unlock(); +} + + /*! + * \brief Draw the Background. + * \details This function actually draws the Background to the Canvas. + * \note On each draw cycle, first any Drawables that have been newly added to the Background will be rendered, and then any new calls to drawPixel will be processed. + */ +void Background::draw() { + if (!complete) { + TsglDebug("Shaders have not been defined for this background."); + return; + } + + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + glEnable(GL_DEPTH_TEST); + + attribMutex.lock(); + if (toClear) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + toClear = false; + } + attribMutex.unlock(); + + glViewport(0,0,myWidth,myHeight); + + drawableMutex.lock(); + for (unsigned int i = 0; i < myDrawables->size(); i++) + { + Drawable* d = (*myDrawables)[i]; + if(d->isProcessed()) { + selectShaders(d->getShaderType()); + if (d->getShaderType() == SHAPE_SHADER_TYPE) { + d->draw(shapeShader); + } else if (d->getShaderType() == TEXTURE_SHADER_TYPE) { + d->draw(textureShader); + } else if (d->getShaderType() == TEXT_SHADER_TYPE) { + d->draw(textShader); + } + } + } + myDrawables->clear(); + drawableMutex.unlock(); + + // setting up texture shaders for both pixel drawing and post-blit render + selectShaders(TEXTURE_SHADER_TYPE); + + glm::mat4 model = glm::mat4(1.0f); + model = glm::scale(model, glm::vec3(myWidth, myHeight, 1)); + + unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + + glClear(GL_DEPTH_BUFFER_BIT); + + // check for new pixels being drawn + pixelBufferMutex.lock(); + if (newPixelsDrawn) { + glBindTexture(GL_TEXTURE_2D, pixelTexture); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixelTextureBuffer); + glGenerateMipmap(GL_TEXTURE_2D); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + newPixelsDrawn = false; + } + pixelBufferMutex.unlock(); + + // blit MSAA framebuffer to non-MSAA framebuffer's texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, myWidth, myHeight, 0, 0, myWidth, myHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0,0,framebufferWidth,framebufferHeight); + + glDisable(GL_DEPTH_TEST); + + glBindTexture(GL_TEXTURE_2D,intermediateTexture); + + // read pixels into buffer for Background::getPixel() + readPixelMutex.lock(); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, readPixelBuffer); + // glPixelStorei(GL_PACK_ALIGNMENT, 4); + readPixelMutex.unlock(); + + // render non-MSAA framebuffer's texture to default framebuffer + glPixelStorei(GL_UNPACK_ALIGNMENT,4); + 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_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + /* next two lines are very essential */ + glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES,0,6); + glEnable(GL_DEPTH_TEST); +} + +/*! \brief Activates the corresponding Shader for a given Drawable. + * \param sType Unsigned int with a corresponding value for each type of Shader. + */ +void Background::selectShaders(unsigned int sType) { + Shader * program = 0; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + unsigned int aspectLoc = glGetUniformLocation(program->ID, "aspect"); + glUniformMatrix4fv(aspectLoc, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)myWidth/(float)myHeight, 0.1f, 5000.0f); + glm::mat4 view = myCamera->getViewMatrix(); + glm::mat4 model = glm::mat4(1.0f); + + glUniformMatrix4fv(glGetUniformLocation(program->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "view"), 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); +} + +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color ColorFloat for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(a); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color Array of ColorFloats for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(a); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color Array of ColorFloats for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color ColorFloat for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color ColorFloat for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color Array of ColorFloats for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color ColorFloat for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color Array of ColorFloats for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color ColorFloat for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(e); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color Array of ColorFloats for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(e); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Image to the Background. + * \details Initializes a new Image based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Image's center location. + * \param y The y coordinate of the Image's center location. + * \param z The z coordinate of the Image's center location. + * \param filename String containing the file location of the Image. + * \param yaw The Image's yaw rotation. + * \param pitch The Image's pitch rotation. + * \param roll The Image's roll rotation. + * \param alpha Alpha value for the Image's transparency. + */ +void Background::drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha) { + Image * i = new Image(x,y,z,filename,width,height,yaw,pitch,roll,alpha); + drawableMutex.lock(); + myDrawables->push(i); + drawableMutex.unlock(); +} + +/*! + * \brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the color of the Line. + */ +void Background::drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color) { + Line * l = new Line(x1,y1,z1,x2,y2,z2,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + +/*! + * \brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color Array of ColorFloats for the Line's vertices. + */ +void Background::drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color[]) { + Line * l = new Line(x1,y1,z1,x2,y2,z2,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color ColorFloat for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color Array of ColorFloats for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + + /*! + * \brief Draws a single pixel, specified in x,y format. + * \details This function alters the value at the specified x, y offset within the Background's buffer variable. + * \note (0,0) signifies the center of the Background. + * \param x The x-position of the pixel. + * \param y The y-position of the pixel. + * \param color The color of the point. + */ +void Background::drawPixel(float x, float y, ColorInt c) { + if (abs((int)x) > (myWidth / 2) || abs((int)y) > (myHeight / 2)) { + TsglErr("Pixel x and y coordinates must be within Background dimensions."); + return; + } + pixelBufferMutex.lock(); + int intX = (int) x + myWidth / 2; + int intY = (int) y + myHeight / 2; + int outR; + int outG; + int outB; + int outA; + // first, if pixel hasn't been written since last draw cycle, just draw + if (pixelTextureBuffer[(intY * myWidth + intX) * 4 + 3] == 0) { + outR = c.R; outG = c.G; outB = c.B; outA = c.A; + } else { + // if new alpha is 255, just replace. otherwise, alpha blend + if (c.A == 255) { + outR = c.R; outG = c.G; outB = c.B; outA = 255; + } else { + int destA = (float) pixelTextureBuffer[(intY * myWidth + intX) * 4 + 3] / 255; + float srcA = (float) c.A / 255; + float oA = srcA + (destA * (1 - srcA)); + outR = (c.R * srcA + pixelTextureBuffer[(intY * myWidth + intX) * 4] * destA * (1 - srcA)) / oA; + outG = (c.G * srcA + pixelTextureBuffer[(intY * myWidth + intX) * 4 + 1] * destA * (1 - srcA)) / oA; + outB = (c.B * srcA + pixelTextureBuffer[(intY * myWidth + intX) * 4 + 2] * destA * (1 - srcA)) / oA; + outA = (int) (oA * 255); + } + } + + pixelTextureBuffer[(intY * myWidth + intX) * 4] = outR; + pixelTextureBuffer[(intY * myWidth + intX) * 4 + 1] = outG; + pixelTextureBuffer[(intY * myWidth + intX) * 4 + 2] = outB; + pixelTextureBuffer[(intY * myWidth + intX) * 4 + 3] = outA; + + newPixelsDrawn = true; + pixelBufferMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color ColorFloat for the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(p); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color Array of ColorFloats corresponding to the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(p); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color ColorFloat for the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color ColorFloat for the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color Array of ColorFloats corresponding to the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color ColorFloat for the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color Array of ColorFloats corresponding to the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color ColorFloat for the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color Array of ColorFloats corresponding to the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws Text to the Background. + * \details Initializes a new Text based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Text's center location. + * \param y The y coordinate of the Text's center location. + * \param z The z coordinate of the Text's center location. + * \param text String containing the characters to be rendered. + * \param fontFilename String containing the filename for the font with which the Text will be rendered. + * \param size The Text's size, relative to worldspace. + * \param yaw The Text's yaw rotation. + * \param pitch The Text's pitch rotation. + * \param roll The Text's roll rotation. + * \param color ColorFloat for the Text. + */ +void Background::drawText(float x, float y, float z, std::string text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color) { + std::wstring wsTmp(text.begin(), text.end()); + std::wstring ws = wsTmp; + drawText(x,y,z,ws,fontFilename,size,yaw,pitch,roll,color); +} + +/*!\brief Procedurally draws Text to the Background. + * \details Initializes a new Text based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Text's center location. + * \param y The y coordinate of the Text's center location. + * \param z The z coordinate of the Text's center location. + * \param text Wide string containing the characters to be rendered. + * \param fontFilename String containing the filename for the font with which the Text will be rendered. + * \param size The Text's size, relative to worldspace. + * \param yaw The Text's yaw rotation. + * \param pitch The Text's pitch rotation. + * \param roll The Text's roll rotation. + * \param color ColorFloat for the Text. + */ +void Background::drawText(float x, float y, float z, std::wstring text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color) { + Text * t = new Text(x,y,z,text,fontFilename,size,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color ColorFloat for the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color ColorFloat for the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color Array of ColorFloats corresponding to the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + + /*! + * \brief Gets the color of the pixel drawn on the current Background at the given x and y. + * \note (0,0) signifies the center of the Background's texture. + * \param x The x-position of the pixel to grab. + * \param y The y-position of the pixel to grab. + * \return A ColorInt containing the color of the pixel at (x,y). + */ +ColorInt Background::getPixel(float x, float y) { + if (abs(x) > (myWidth/2) || abs(y) > (myHeight/2)) { + TsglErr("Accessor x and y must be within Canvas parameters."); + return ColorInt(0,0,0,0); + } + readPixelMutex.lock(); + int intX = (int) x + myWidth/2; + int intY = (int) y + myHeight/2; + int off = 3 * (intY * myWidth + intX); + ColorInt c = ColorInt(readPixelBuffer[off], readPixelBuffer[off + 1], readPixelBuffer[off + 2], 255); + readPixelMutex.unlock(); + return c; +} + +/*! \brief Mutator for the color used to clear the Background when clear() is called. + * \details Sets the clear color to the parameter ColorFloat. + * \param c ColorFloat assigned to the clear color of the Background. + */ +void Background::setClearColor(ColorFloat c) { + attribMutex.lock(); + baseColor = c; + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + attribMutex.unlock(); +} + +/*! +* \brief Destructor for the Background. +*/ +Background::~Background() { + myDrawables->clear(); + delete [] readPixelBuffer; + delete [] pixelTextureBuffer; + delete [] vertices; + delete myDrawables; + glDeleteTextures(1, &intermediateTexture); + glDeleteFramebuffers(1, &intermediateFBO); + glDeleteTextures(1, &multisampledTexture); + glDeleteFramebuffers(1, &multisampledFBO); +} + +} \ No newline at end of file diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h new file mode 100644 index 000000000..6a60378bb --- /dev/null +++ b/src/TSGL/Background.h @@ -0,0 +1,172 @@ +/* + * Background.h provides a class for drawing TSGL primitives procedurally onto a background. + */ + +#ifndef BACKGROUND_H_ +#define BACKGROUND_H_ + +#include "Camera.h" + +#include "Array.h" // Our own array for buffering drawing operations +#include "Arrow.h" +#include "Circle.h" +#include "ConcavePolygon.h" +#include "ConvexPolygon.h" +#include "Ellipse.h" +#include "Image.h" +#include "Line.h" +#include "Polyline.h" +#include "Rectangle.h" +#include "RegularPolygon.h" +#include "Square.h" +#include "Star.h" +#include "Text.h" +#include "Triangle.h" +#include "TriangleStrip.h" +#include "Util.h" // Needed constants and has cmath for performing math operations + +namespace tsgl { + +/*! \class Background + * \brief Draw a Background for the Canvas with colored pixels. + * \details Background is a class for holding colored pixel data. + */ +class Background { +protected: + GLint myWidth, myHeight; + GLint framebufferWidth, framebufferHeight; + GLfloat myWorldZ; + + GLuint multisampledTexture, intermediateTexture; + GLuint multisampledFBO, intermediateFBO; + GLuint RBO; + + Array * myDrawables; + + Camera * myCamera; + + Shader * textShader; + Shader * shapeShader; + Shader * textureShader; + + ColorFloat baseColor; + bool toClear; + + std::mutex readPixelMutex; + uint8_t* readPixelBuffer; + + std::mutex pixelBufferMutex; + GLuint pixelTexture; + uint8_t* pixelTextureBuffer; + bool newPixelsDrawn; + + bool complete; + std::mutex attribMutex; + std::mutex drawableMutex; + + GLfloat * vertices; + + virtual void selectShaders(unsigned int sType); +public: + Background(GLint width, GLint height, const ColorFloat &c = WHITE); + + virtual void init(Shader * shapeS, Shader * textS, Shader * textureS, Camera * camera, GLFWwindow * window); + + virtual bool isInitialized() { return complete; } + + virtual void clear() { attribMutex.lock(); toClear = true; attribMutex.unlock(); } + + virtual void draw(); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false, bool outlined = false); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha = 1.0f); + + virtual void drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawPixel(float x, float y, ColorInt c); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja = false, bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja = false, bool outlined = false); + + virtual void drawText(float x, float y, float z, std::string text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color); + + virtual void drawText(float x, float y, float z, std::wstring text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + /*! + * \brief Accessor for the pixel width of the Background. + * \details Returns the value of the myWidth private variable, a GLint. + */ + virtual GLint getWidth() { return myWidth; } + + /*! + * \brief Accessor for the pixel height of the Background. + * \details Returns the value of the myHeight private variable, a GLint. + */ + virtual GLint getHeight() { return myHeight; } + + virtual ColorInt getPixel(float x, float y); + + /*! + * \brief Accessor for color which is used to clear the Background when clear() is called. + * \details Returns a ColorInt corresponding to the clear color of the Background. + */ + virtual ColorFloat getClearColor() { return baseColor; } + + virtual void setClearColor(ColorFloat c); + + virtual ~Background(); +}; + +} + +#endif /* BACKGROUND_H_ */ \ No newline at end of file diff --git a/src/TSGL/Camera.cpp b/src/TSGL/Camera.cpp new file mode 100644 index 000000000..91447cd60 --- /dev/null +++ b/src/TSGL/Camera.cpp @@ -0,0 +1,479 @@ +#include "Camera.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Camera. + * \details Explicit constructor for a Camera object. + * \param position The Camera's location in 3D space, a glm::vec3. + * \param up A 3D vector indicating the up direction in world space. + * \param target The point at which the Camera will look. + * \return A new Camera object, used to represent and return a corresponding view matrix. + */ +Camera::Camera(glm::vec3 position, glm::vec3 up, glm::vec3 target) { + attribMutex.lock(); + myPosition = position; + myWorldUp = up; + myFront = glm::normalize(target - myPosition); + myRight = glm::normalize(glm::cross(myFront, myWorldUp)); + myUp = glm::cross(myRight, myFront); + myPitch = glm::degrees(asin(myFront.y)); + // a simple acos() doesn't really cut it... undefined in some places + wrongly signed elsewhere + if (myFront.z == 0) { + if (myFront.x > 0) { + myYaw = 0; + } else { + myYaw = 180; + } + } else if (myFront.z > 0) { + myYaw = glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } else { + myYaw = -glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Camera. + * \details Explicit constructor for a Camera object. + * \param posX The Camera's positional x-coordinate in 3D space, a float. + * \param posY The Camera's positional y-coordinate in 3D space, a float. + * \param posZ The Camera's positional z-coordinate in 3D space, a float. + * \param upX The x-component of a 3D vector indicating the up direction in world space. + * \param upY The y-component of a 3D vector indicating the up direction in world space. + * \param upZ The z-component of a 3D vector indicating the up direction in world space. + * \param targetX The x-coordinate of the point at which the Camera will look. + * \param targetY The y-coordinate of the point at which the Camera will look. + * \param targetZ The z-coordinate of the point at which the Camera will look. + * \return A new Camera object, used to represent and return a corresponding view matrix. + */ +Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float targetX, float targetY, float targetZ) { + attribMutex.lock(); + myPosition = glm::vec3(posX, posY, posZ); + myWorldUp = glm::vec3(upX, upY, upZ); + myFront = glm::normalize(glm::vec3(targetX, targetY, targetZ) - myPosition); + myRight = glm::normalize(glm::cross(myFront, myWorldUp)); + myUp = glm::cross(myRight, myFront); + myPitch = glm::degrees(asin(myFront.y)); + // a simple acos() doesn't really cut it... undefined in some places + wrongly signed elsewhere + if (myFront.z == 0) { + if (myFront.x > 0) { + myYaw = 0; + } else { + myYaw = 180; + } + } else if (myFront.z > 0) { + myYaw = glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } else { + myYaw = -glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Camera. + * \details Explicit constructor for a Camera object. + * \param position The Camera's location in 3D space, a glm::vec3. + * \param up A 3D vector indicating the up direction in world space. + * \param yaw The camera's yaw rotation (horizontal) in degrees. + * \param pitch The camera's pitch rotation (vertical) in degrees. + * \note With position.x and position.y equal to 0 and a positive position.z, a yaw of -90 degrees and pitch of 0 degrees will look at (0,0,0). + * \note pitch is constrained between -89 and 89 degrees. + * \return A new Camera object, used to represent and return a corresponding view matrix. + */ +Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch) { + attribMutex.lock(); + myPosition = position; + myWorldUp = up; + myYaw = yaw; + if (pitch > 89.0f) { + myPitch = 89.0f; + } else if (pitch < -89.0f) { + myPitch = -89.0f; + } else { + myPitch = pitch; + } + updateCameraAngle(); + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Camera. + * \details Explicit constructor for a Camera object. + * \param posX The Camera's positional x-coordinate in 3D space, a float. + * \param posY The Camera's positional y-coordinate in 3D space, a float. + * \param posZ The Camera's positional z-coordinate in 3D space, a float. + * \param upX The x-component of a 3D vector indicating the up direction in world space. + * \param upY The y-component of a 3D vector indicating the up direction in world space. + * \param upZ The z-component of a 3D vector indicating the up direction in world space. + * \param yaw The camera's yaw rotation (horizontal) in degrees. + * \param pitch The camera's pitch rotation (vertical) in degrees. + * \note With posX and posY equal to 0 and a positive posZ, a yaw of -90 degrees and pitch of 0 degrees will look at (0,0,0). + * \note pitch is constrained between -89 and 89 degrees. + * \return A new Camera object, used to represent and return a corresponding view matrix. + */ +Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) { + attribMutex.lock(); + myPosition = glm::vec3(posX, posY, posZ); + myWorldUp = glm::vec3(upX, upY, upZ); + myYaw = yaw; + if (pitch > 89.0f) { + myPitch = 89.0f; + } else if (pitch < -89.0f) { + myPitch = -89.0f; + } else { + myPitch = pitch; + } + updateCameraAngle(); + attribMutex.unlock(); +} + + /*! + * \brief Accessor for the corresponding view matrix for the Camera. + * \details Returns a glm::mat4 based on Camera's position and orientation. + * \return A glm::mat4 calculated by glm::lookAt(). + */ +glm::mat4 Camera::getViewMatrix() { + attribMutex.lock(); + glm::mat4 v = glm::lookAt(myPosition, myPosition + myFront, myUp); + attribMutex.unlock(); + return v; +} + + /*! + * \brief Mutator for Camera's x-coordinate in world space. + * \details Alters the x component of Camera's myPosition vector by delta. + * \param delta The difference between camera's new and old x-coordinates. + */ +void Camera::changeXBy(float delta) { + attribMutex.lock(); + myPosition += glm::vec3(delta,0.0f,0.0f); + attribMutex.unlock(); +} + + /*! + * \brief Mutator for Camera's y-coordinate in world space. + * \details Alters the y component of Camera's myPosition vector by delta. + * \param delta The difference between camera's new and old y-coordinates. + */ +void Camera::changeYBy(float delta) { + attribMutex.lock(); + myPosition += glm::vec3(0.0f,delta,0.0f); + attribMutex.unlock(); +} + + /*! + * \brief Mutator for Camera's z-coordinate in world space. + * \details Alters the z component of Camera's myPosition vector by delta. + * \param delta The difference between camera's new and old z-coordinates. + */ +void Camera::changeZBy(float delta) { + attribMutex.lock(); + myPosition += glm::vec3(0.0f,0.0f,delta); + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera backward, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the opposite direction of its myFront vector. + * \param delta How far backwards to move the Camera, in world space. + */ +void Camera::moveBackward(float delta) { + attribMutex.lock(); + myPosition -= myFront * delta; + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera forward, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the same direction as its myFront vector. + * \param delta How far forward to move the Camera, in world space. + */ +void Camera::moveForward(float delta) { + attribMutex.lock(); + myPosition += myFront * delta; + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera downward, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the opposite direction of its myUp vector. + * \param delta How far downward to move the Camera, in world space. + */ +void Camera::moveDown(float delta) { + attribMutex.lock(); + myPosition -= myUp * delta; + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera upward, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the same direction as its myUp vector. + * \param delta How far upward to move the Camera, in world space. + */ +void Camera::moveUp(float delta) { + attribMutex.lock(); + myPosition += myUp * delta; + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera left, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the opposite direction of its myRight vector. + * \param delta How far left to move the Camera, in world space. + */ +void Camera::moveLeft(float delta) { + attribMutex.lock(); + myPosition -= myRight * delta; + attribMutex.unlock(); +} + + /*! + * \brief Moves the Camera right, relative to its orientation, by delta. + * \details Alters Camera's myPosition vector by delta, in the same direction as its myUp vector. + * \param delta How far right to move the Camera, in world space. + */ +void Camera::moveRight(float delta) { + attribMutex.lock(); + myPosition += myRight * delta; + attribMutex.unlock(); +} + + /*! + * \brief Alters the Camera's position in world space. + * \details Sets the x, y, and z components of Camera's myPosition vector according to the parameters. + * \param pos 3D vector containing Camera's new x, y, and z positional coordinates. + */ +void Camera::setPosition(glm::vec3 pos) { + attribMutex.lock(); + myPosition = pos; + attribMutex.unlock(); +} + + /*! + * \brief Alters the Camera's position in world space. + * \details Sets the x, y, and z components of Camera's myPosition vector according to the parameters. + * \param x The Camera's new x-coordinate in world space. + * \param y The Camera's new y-coordinate in world space. + * \param z The Camera's new z-coordinate in world space. + */ +void Camera::setPosition(float x, float y, float z) { + attribMutex.lock(); + myPosition = glm::vec3(x,y,z); + attribMutex.unlock(); +} + + /*! + * \brief Sets the Camera's x-coordinate in world space. + * \details Sets the x component of Camera's myPosition vector equal to the parameter. + * \param x The Camera's new x-coordinate in world space. + */ +void Camera::setPositionX(float x) { + attribMutex.lock(); + myPosition.x = x; + attribMutex.unlock(); +} + + /*! + * \brief Sets the Camera's y-coordinate co in world space. + * \details Sets the y component of Camera's myPosition vector equal to the parameter. + * \param y The Camera's new y-coordinate in world space. + */ +void Camera::setPositionY(float y) { + attribMutex.lock(); + myPosition.y = y; + attribMutex.unlock(); +} + + /*! + * \brief Sets the Camera's z-coordinate in world space. + * \details Sets the z component of Camera's myPosition vector equal to the parameter. + * \param z The Camera's new z-coordinate in world space. + */ +void Camera::setPositionZ(float z) { + attribMutex.lock(); + myPosition.z = z; + attribMutex.unlock(); +} + + /*! + * \brief Alters the point at which the Camera looks in world space. + * \details Sets Camera's myFront vector, myRight vector, myUp vector, myPitch, and myYaw based on the parameters. + * \param x The new x-coordinate at which Camera looks, in world space. + * \param y The new y-coordinate at which Camera looks, in world space. + * \param z The new z-coordinate at which Camera looks, in world space. + */ +void Camera::lookAt(float x, float y, float z) { + attribMutex.lock(); + myFront = glm::normalize(glm::vec3(x,y,z) - myPosition); + myRight = glm::normalize(glm::cross(myFront, myWorldUp)); + myUp = glm::cross(myRight, myFront); + myPitch = glm::degrees(asin(myFront.y)); + if (myFront.z == 0) { + if (myFront.x > 0) { + myYaw = 0; + } else { + myYaw = 180; + } + } else if (myFront.z > 0) { + myYaw = glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } else { + myYaw = -glm::degrees( acos(myFront.x / cos(glm::radians(myPitch))) ); + } + attribMutex.unlock(); +} + +/*! + * \brief Alters the Camera's yaw rotation. + * \details Based on the original direction the Camera was set to face, the Camera is rotated according to the parameter. + * \param delta The amount by which to change the Camera's yaw, in degrees. + */ +void Camera::changeYawBy(float delta) { + attribMutex.lock(); + myYaw += delta; + updateCameraAngle(); + attribMutex.unlock(); +} + +/*! + * \brief Alters the Camera's pitch rotation. + * \details Based on the original direction the Camera was set to face, the Camera is rotated according to the parameter. + * \param delta The amount by which to change the Camera's pitch, in degrees. + * \note pitch is constrained between -89 and 89 degrees. + */ +void Camera::changePitchBy(float delta) { + attribMutex.lock(); + myPitch += delta; + if (myPitch > 89.0f) + myPitch = 89.0f; + if (myPitch < -89.0f) + myPitch = -89.0f; + updateCameraAngle(); + attribMutex.unlock(); +} + +/*! + * \brief Accessor for the Camera's pitch. + * \details Returns the value of the myPitch instance variable + */ +float Camera::getPitch() { + attribMutex.lock(); + float p = myPitch; + attribMutex.unlock(); + return p; +} + +/*! + * \brief Accessor for the Camera's yaw. + * \details Returns the value of the myYaw instance variable + */ +float Camera::getYaw() { + attribMutex.lock(); + float y = myYaw; + attribMutex.unlock(); + return y; +} + +/*! + * \brief Accessor for the Camera's position in world space. + * \details Returns the value of the myPosition instance variable + */ +glm::vec3 Camera::getPosition() { + attribMutex.lock(); + glm::vec3 p = myPosition; + attribMutex.unlock(); + return p; +} + +/*! + * \brief Accessor for the x-coordinate of the Camera's position in world space. + * \details Returns the x component of the myPosition instance variable + */ +float Camera::getPositionX() { + attribMutex.lock(); + float x = myPosition.x; + attribMutex.unlock(); + return x; +} + +/*! + * \brief Accessor for the y-coordinate of the Camera's position in world space. + * \details Returns the y component of the myPosition instance variable + */ +float Camera::getPositionY() { + attribMutex.lock(); + float y = myPosition.y; + attribMutex.unlock(); + return y; +} + +/*! + * \brief Accessor for the z-coordinate of the Camera's position in world space. + * \details Returns the z component of the myPosition instance variable + */ +float Camera::getPositionZ() { + attribMutex.lock(); + float z = myPosition.z; + attribMutex.unlock(); + return z; +} + +/*! + * \brief Accessor for the point at which Camera looks in world space. + * \details Returns the sum of the myPosition and myFront instance variables + */ +glm::vec3 Camera::getTarget() { + attribMutex.lock(); + glm::vec3 t = myPosition + myFront; + attribMutex.unlock(); + return t; +} + +/*! + * \brief Accessor for the x-coordinate of the point at which Camera looks in world space. + * \details Returns the x component of the sum of the myPosition and myFront instance variables + */ +float Camera::getTargetX() { + attribMutex.lock(); + glm::vec3 t = myPosition + myFront; + attribMutex.unlock(); + return t.x; +} + +/*! + * \brief Accessor for the y-coordinate of the point at which Camera looks in world space. + * \details Returns the y component of the sum of the myPosition and myFront instance variables + */ +float Camera::getTargetY() { + attribMutex.lock(); + glm::vec3 t = myPosition + myFront; + attribMutex.unlock(); + return t.y; +} + +/*! + * \brief Accessor for the z-coordinate of the point at which Camera looks in world space. + * \details Returns the z component of the sum of the myPosition and myFront instance variables + */ +float Camera::getTargetZ() { + attribMutex.lock(); + glm::vec3 t = myPosition + myFront; + attribMutex.unlock(); + return t.z; +} + +/*! + * \brief Protected helper method that recalculates Camera's myFront vector based on yaw and pitch. + * \details Alters myFront, myRight, and myUp according to yaw and pitch. + */ +void Camera::updateCameraAngle() { + glm::vec3 front; + front.x = cos(glm::radians(myYaw)) * cos(glm::radians(myPitch)); + front.y = sin(glm::radians(myPitch)); + front.z = sin(glm::radians(myYaw)) * cos(glm::radians(myPitch)); + myFront = glm::normalize(front); + myRight = glm::normalize(glm::cross(myFront, myWorldUp)); // normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement. + myUp = glm::normalize(glm::cross(myRight, myFront)); +} + +} \ No newline at end of file diff --git a/src/TSGL/Camera.h b/src/TSGL/Camera.h new file mode 100644 index 000000000..e7c1d4501 --- /dev/null +++ b/src/TSGL/Camera.h @@ -0,0 +1,106 @@ +/* + * Camera.h provides a way to control the view matrix for a Canvas. + */ + +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include +#include +#include +#include +#include "Util.h" // Needed constants and has cmath for performing math operations + +namespace tsgl { + +/*! \class Camera + * \brief Defines a movable, rotatable camera-like object and its corresponding view matrix. + * \details Camera is used within TSGL::Canvas to define the view matrix. + */ +class Camera { +protected: + // camera Attributes + glm::vec3 myPosition; + glm::vec3 myFront; + glm::vec3 myUp; + glm::vec3 myRight; + glm::vec3 myWorldUp; + float myYaw; + float myPitch; + + std::mutex attribMutex; + + void updateCameraAngle(); +public: + Camera(glm::vec3 position, glm::vec3 up, glm::vec3 target); + + Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float targetX, float targetY, float targetZ); + + Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch); + + Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch); + + // returns the view matrix calculated using the LookAt Matrix + glm::mat4 getViewMatrix(); + + /* POSITION VECTOR MUTATORS */ + void changeXBy(float delta); + + void changeYBy(float delta); + + void changeZBy(float delta); + + void moveBackward(float delta); + + void moveForward(float delta); + + void moveDown(float delta); + + void moveUp(float delta); + + void moveLeft(float delta); + + void moveRight(float delta); + + void setPosition(glm::vec3 pos); + + void setPosition(float x, float y, float z); + + void setPositionX(float x); + + void setPositionY(float y); + + void setPositionZ(float z); + + /* TARGET VECTOR MUTATORS */ + void lookAt(float x, float y, float z); + + void changeYawBy(float delta); + + void changePitchBy(float delta); + + /* ACCESSORS */ + float getPitch(); + + float getYaw(); + + glm::vec3 getPosition(); + + float getPositionX(); + + float getPositionY(); + + float getPositionZ(); + + glm::vec3 getTarget(); + + float getTargetX(); + + float getTargetY(); + + float getTargetZ(); +}; + +} + +#endif /* CAMERA_H_ */ \ No newline at end of file diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index b7bd617e8..795c1b735 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -1,53 +1,90 @@ #include "Canvas.h" +// From stb_image.h: +// Do this: +// #define STB_IMAGE_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the implementation. + #ifndef STB_DEFINE + #define STB_IMAGE_WRITE_IMPLEMENTATION + #include "stb/stb_image_write.h" + #define STB_IMAGE_IMPLEMENTATION + #include "stb/stb_image.h" + #define STB_DEFINE + #endif + namespace tsgl { // Shader sources -static const GLchar* vertexSource = - "#version 150 core\n" - "in vec2 position;" - "in vec4 color;" - "out vec4 Color;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" - "}"; -static const GLchar* fragmentSource = - "#version 150\n" - "in vec4 Color;" - "out vec4 outColor;" - "void main() {" - " outColor = vec4(Color);" - "}"; -static const GLchar* textureVertexSource = - "#version 150 core\n" - "in vec2 position;" - "in vec4 color;" - "in vec2 texcoord;" - "out vec4 Color;" - "out vec2 Texcoord;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Texcoord = texcoord;" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" - "}"; -static const GLchar* textureFragmentSource = - "#version 150\n" - "in vec4 Color;" - "in vec2 Texcoord;" - "out vec4 outColor;" - "uniform sampler2D tex;" - "void main() {" - " outColor = texture(tex, Texcoord) * vec4(Color);" - "}"; - -int Canvas::drawBuffer = GL_FRONT_LEFT; + +static const GLchar* shapeVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec4 aColor;" + "out vec4 color;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * vec4(aPos, 1.0);" + "color = aColor;" + "}"; + +static const GLchar* shapeFragmentShader = + "#version 330 core\n" + "out vec4 FragColor;" + "in vec4 color;" + "void main() {" + "FragColor = color;" + "}"; + +static const GLchar* textVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec2 aTexCoord;" + "out vec2 TexCoords;" + "uniform mat4 aspect;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * aspect * vec4(aPos, 1.0);" + "TexCoords = vec2(aTexCoord.x, aTexCoord.y);" + "}"; + +static const GLchar* textFragmentShader = + "#version 330 core\n" + "in vec2 TexCoords;" + "out vec4 FragColor;" + "uniform sampler2D text;" + "uniform vec4 textColor;" + "void main() {" + "vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);" + "FragColor = textColor * sampled;" + "}"; + +static const GLchar* textureVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec2 aTexCoord;" + "out vec2 TexCoords;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * vec4(aPos, 1.0);" + "TexCoords = vec2(aTexCoord.x, aTexCoord.y);" + "}"; + +static const GLchar* textureFragmentShader = + "#version 330 core\n" + "out vec4 FragColor;" + "in vec2 TexCoords;" + "uniform sampler2D texture1;" + "uniform float alpha;" + "void main() {" + "FragColor = texture(texture1, TexCoords) * vec4(1.0,1.0,1.0,alpha);" + "}"; + bool Canvas::glfwIsReady = false; std::mutex Canvas::glfwMutex; GLFWvidmode const* Canvas::monInfo; @@ -62,8 +99,8 @@ unsigned Canvas::openCanvases = 0; * The created Canvas will take up approximately 90% of the monitor's height, and will * have a 4:3 aspect ratio. */ -Canvas::Canvas(double timerLength) { - init(-1, -1, -1, -1, -1, "", timerLength); +Canvas::Canvas(double timerLength, Background * bg) { + init(-1, -1, -1, -1, "", GRAY, bg, timerLength); } /*! @@ -78,8 +115,8 @@ Canvas::Canvas(double timerLength) { * A value less than or equal to 0 sets it to automatic. * \return A new Canvas with the specified position, dimensions, title, and draw cycle length. */ -Canvas::Canvas(int x, int y, int width, int height, std::string title, double timerLength) { - init(x, y, width, height, width*height*2, title, timerLength); +Canvas::Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor, Background * background, double timerLength) { + init(x, y, width, height, title, backgroundColor, background, timerLength); } /*! @@ -89,12 +126,12 @@ Canvas::Canvas(int x, int y, int width, int height, std::string title, double ti */ Canvas::~Canvas() { // Free our pointer memory - delete myDrawables; - delete drawableBuffer; - delete[] proceduralBuffer; delete drawTimer; - delete[] vertexData; + delete camera; delete [] screenBuffer; + if (defaultBackground) { + delete myBackground; + } if (--openCanvases == 0) { glfwIsReady = false; glfwTerminate(); // Terminate GLFW @@ -136,8 +173,10 @@ void Canvas::buttonCallback(GLFWwindow* window, int button, int action, int mods * \brief Clears the Canvas. * \details This function clears the screen to the color specified in setBackgroundColor(). */ -void Canvas::clearProcedural() { - drawRectangle(0,0,getWindowWidth(),getWindowHeight(),getBackgroundColor()); +void Canvas::clearBackground() { + backgroundMutex.lock(); + myBackground->clear(); + backgroundMutex.unlock(); } /*! @@ -148,6 +187,7 @@ void Canvas::clearProcedural() { */ void Canvas::close() { glfwSetWindowShouldClose(window, GL_TRUE); + toClose = true; TsglDebug("Window closed successfully."); } @@ -157,17 +197,12 @@ void Canvas::close() { /** * \brief Adds a Drawable to the Canvas. - * \details If the Drawable's layer has not been set, it will default to currentNewShapeLayerDefault, - * which can be set through setDefaultLayer(). + * \details Adds the parameter drawable to objectBuffer. * \param shapePtr Pointer to the Drawable to add to this Canvas. */ void Canvas::add(Drawable * shapePtr) { objectMutex.lock(); objectBuffer.push_back(shapePtr); - objectBufferEmpty = false; - std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { - return (a->getLayer() < b->getLayer()); // true if A's layer is higher than B's layer - }); objectMutex.unlock(); } @@ -201,190 +236,95 @@ void Canvas::clearObjectBuffer(bool shouldFreeMemory) { objectBuffer.clear(); } -void Canvas::draw() { +void Canvas::draw() +{ + windowMutex.lock(); + glfwMakeContextCurrent(window); // Reset the window glfwSetWindowShouldClose(window, GL_FALSE); + glfwMakeContextCurrent(NULL); + windowMutex.unlock(); - // Get actual framebuffer size and adjust scaling accordingly - int fbw, fbh; - glfwGetFramebufferSize(window, &fbw, &fbh); - int scaling = round((1.0f*fbw)/winWidth); - - if (hasStereo) - Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); - else - Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); - - - setBackgroundColor(bgcolor); //Set our initial clear / background color - // glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - readyToDraw = true; - bool newThingDrawn = true; //Always draw the first frame - int frame = 0; + bool captureScreen = false; - // Start the drawing loop - for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { + for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) + { + // this if, and the capturescreen variable, are necessary for screenshots to be 100% correct. + if (toRecord > 0) { + captureScreen = true; + --toRecord; + } drawTimer->sleep(true); syncMutex.lock(); - int leftWindowIndex; - #ifdef __APPLE__ - leftWindowIndex = 0; windowMutex.lock(); - #else - leftWindowIndex = -1; #endif - glfwMakeContextCurrent(window); // We're drawing to window as soon as it's created + glfwMakeContextCurrent(window); realFPS = round(1 / drawTimer->getTimeBetweenSleeps()); if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; std::cout.flush(); - bufferMutex.lock(); // Time to flush our buffer - if (drawableBuffer->size() > 0) { // But only if there is anything to flush - newThingDrawn = true; - for (unsigned int i = 0; i < drawableBuffer->size(); i++) - myDrawables->push((*drawableBuffer)[i]); - drawableBuffer->shallowClear(); // We want to clear the buffer but not delete those objects as we still need to draw them - } - bufferMutex.unlock(); - - int pos = pointBufferPosition; - int posLast = pointLastPosition; - - if (loopAround || pos != posLast) - newThingDrawn = true; - - if (newThingDrawn || !objectBufferEmpty) { - - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - glViewport(0,0,winWidth,winHeight); - - if (frame == 0 || !objectBufferEmpty) { - glClear(GL_COLOR_BUFFER_BIT); - if(frame > 1) { - textureShaders(true); - loader.drawGLtextureFromBuffer(proceduralBuffer, leftWindowIndex, 0, winWidth, winHeight, GL_RGB); - textureShaders(false); - } - } - - if(frame > 0) { - unsigned int size = myDrawables->size(); - for (unsigned int i = 0; i < size; i++) { - Drawable* d = (*myDrawables)[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - textureShaders(true); - d->draw(); - textureShaders(false); - } - } - } - - if (loopAround) { - newThingDrawn = true; - int toend = myDrawables->capacity() - posLast; - glBufferData(GL_ARRAY_BUFFER, toend * 6 * sizeof(float), - &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, toend); - posLast = 0; - loopAround = false; - } - int pbsize = pos - posLast; - if (pbsize > 0) { - newThingDrawn = true; - glBufferData(GL_ARRAY_BUFFER, pbsize * 6 * sizeof(float), &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, pbsize); - } - pointLastPosition = pos; - } + // clear default framebuffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if(frame > 0) { - if(newThingDrawn) { - glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, proceduralBuffer); - } - // Reset drawn status for the next frame - newThingDrawn = false; - frame = 2; - } else { - frame = 1; + // if background initialized draw it using its multisampled framebuffer + backgroundMutex.lock(); + if (myBackground) + if (myBackground->isInitialized()) { + myBackground->draw(); } - - if (objectBuffer.size() > 0) { - for (unsigned int i = 0; i < objectBuffer.size(); i++) { - Drawable* d = objectBuffer[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - textureShaders(true); - d->draw(); - textureShaders(false); - } + backgroundMutex.unlock(); + + // Scale to window size + glViewport(0, 0, framebufferWidth, framebufferHeight); + // winWidth = windowWidth; + // winHeight = windowHeight; + + objectMutex.lock(); + if (objectBuffer.size() > 0) { + // sort between opaques and transparents and then sort by center z. depth buffer takes care of the rest. not perfect, but good. + std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [this](Drawable * a, Drawable * b)->bool { + if (a->getAlpha() == 1.0 && b->getAlpha() != 1.0) + return true; + else if (a->getAlpha() != 1.0 && b->getAlpha() == 1.0) + return false; + else + return (distanceBetween(a->getCenterX(), a->getCenterY(), a->getCenterZ(), camera->getPositionX(), camera->getPositionY(), camera->getPositionZ()) + > distanceBetween(b->getCenterX(), b->getCenterY(), b->getCenterZ(), camera->getPositionX(), camera->getPositionY(), camera->getPositionZ())); + }); + for (unsigned int i = 0; i < objectBuffer.size(); i++) { + Drawable* d = objectBuffer[i]; + if(d->isProcessed()) { + selectShaders(d->getShaderType()); + if (d->getShaderType() == SHAPE_SHADER_TYPE) { + d->draw(shapeShader); + } else if (d->getShaderType() == TEXTURE_SHADER_TYPE) { + d->draw(textureShader); + } else if (d->getShaderType() == TEXT_SHADER_TYPE) { + d->draw(textShader); } } - } else { - objectBufferEmpty = true; } } - - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - if(frame > 1) { - myDrawables->clear(); // Clear our buffer of shapes to be drawn - } - - /* not sure what the point of this chunk is. */ - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // screenshots and testing - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); - if (toRecord > 0) { + objectMutex.unlock(); + + if (captureScreen) { + // Update our screenBuffer copy with the default framebuffer + screenBufferMutex.lock(); + glViewport(0,0,framebufferWidth,framebufferHeight); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, framebufferWidth, framebufferHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); + screenBufferMutex.unlock(); screenShot(); - --toRecord; + captureScreen = false; } - - /* very vital */ - glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - /* apparently not very vital at all */ - glDrawBuffer(drawBuffer); - - textureShaders(true); - const float vertices[32] = { - 0, 0, 1,1,1,1,0,1, - winWidth,0, 1,1,1,1,1,1, - 0, winHeight,1,1,1,1,0,0, - winWidth,winHeight,1,1,1,1,1,0 - }; - glBindTexture(GL_TEXTURE_2D,renderedTexture); - /* these 5 lines don't seem to do anything */ - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - 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_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - /* next two lines are very essential */ - glBufferData(GL_ARRAY_BUFFER,32*sizeof(float),vertices,GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP,0,4); - glFlush(); // Flush buffer data to the actual draw buffer - glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - - textureShaders(false); + + // Update Screen + glfwSwapBuffers(window); #ifndef __APPLE__ glfwPollEvents(); // Handle any I/O @@ -401,1340 +341,32 @@ void Canvas::draw() { } } - /*! - * \brief Draws a monocolored arrow. - * \details This function draws an arrow with the given endpoints, color, and doubleheaded status - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color A single color for the arrow. - * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. - */ -void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow) { - Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); - drawDrawable(arrow); -} - - /*! - * \brief Draws a multicolored arrow. - * \details This function draws an arrow with the given endpoints, color, and doubleheaded status - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array of colors for the circle. - * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. - */ -void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow) { - Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); - drawDrawable(arrow); -} - - /*! - * \brief Draws a monocolored filled or outlined circle. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color A single color for the circle. - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat color, bool filled) { - Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined circle. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color An array of colors for the circle. - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat color[], bool filled) { - Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A single color for circle's fill vertices. - * \param outlineColor A single color for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for circle's fill vertices. - * \param outlineColor A single color for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A single color for circle's fill vertices. - * \param outlineColor An array of colors for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for circle's fill vertices. - * \param outlineColor An array of colors for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined concave polygon. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param color A single color for the said vertices. - * \param filled Whether the ConcavePolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined concave polygon. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConcavePolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with different monocolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with multicolored fill and monocolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with monocolored fill and multicolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with different multicolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined convex polygon. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param color A single color for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined convex polygon. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with different monocolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with multicolored fill and monocolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with monocolored fill and multicolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with different multicolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - -/*! - * \brief Draws a Drawable object - * \details This function pushes any Drawable object onto the drawable buffer - * \param d The Drawable object to be drawn - * \note protected method - */ -void Canvas::drawDrawable(Drawable* d) { - if (!started) { - TsglDebug("No drawing before Canvas is started! Ignoring draw request."); - return; - } - while (!readyToDraw) - sleep(); - bufferMutex.lock(); - drawableBuffer->push(d); // Push it onto our drawing buffer - bufferMutex.unlock(); -} - - /*! - * \brief Draws a monocolored filled or outlined ellipse. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param color A single color for ellipse. - * \param filled Whether the ellipse should be filled - * (set to true by default). - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a multicolored filled or outlined ellipse. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param color An array of colors for ellipse. - * \param filled Whether the ellipse should be filled - * (set to true by default). - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with different monocolored fill and outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor A single color for ellipse's fill vertices. - * \param outlineColor A single color for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with multicolored fill and monocolored outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor An array of colors for ellipse's fill vertices. - * \param outlineColor A single color for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with monocolored fill and multicolored outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor A single color for ellipse's fill vertices. - * \param outlineColor An array of colors for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with different multicolored fill and outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor An array of colors for ellipse's fill vertices. - * \param outlineColor An array of colors for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws an image. - * \details This function draws an Image with the given coordinates and dimensions. - * \param filename The name of the file to load the image from. - * \param x The x coordinate of the Image's left edge. - * \param y The y coordinate of the Image's top edge. - * \param width The width of the Image. - * \param height The height of the Image. - * \param alpha The alpha with which to draw the Image - * \param rotation Rotation of the Image in radians clockwise. - */ -void Canvas::drawImage(std::string filename, int x, int y, int width, int height, float alpha, float rotation) { - Image* im = new Image(filename, loader, x, y, width, height, alpha); // Creates the Image with the specified coordinates - im->setRotation(rotation); - drawDrawable(im); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color The color of the line - * (set to BLACK by default). - * \param rotation Rotation of the line in radians clockwise. - */ -void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color, float rotation) { - Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color - l->setRotation(rotation); - drawDrawable(l); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color A color array for the line. - * \param rotation Rotation of the line in radians clockwise. - */ -void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation) { - Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color - l->setRotation(rotation); - drawDrawable(l); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a single pixel, specified in row,column format. - * \details This function draws a pixel at the given screen coordinates with the given color. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. - * \param row The row (y-position) of the pixel. - * \param col The column (x-position) of the pixel. - * \param color The color of the point (set to BLACK by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \see drawPoint() - */ -inline void Canvas::drawPixel(int row, int col, ColorFloat color) { - drawPoint(col, row, color); -} - - /*! - * \brief Draws a single pixel, specified in x,y format. - * \details This function draws a pixel at the given Cartesian coordinates with the given color. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. - * \param x The x position of the point. - * \param y The y position of the point. - * \param color The color of the point (set to BLACK by default). - * \see drawPixel() - */ -void Canvas::drawPoint(int x, int y, ColorFloat color) { - pointArrayMutex.lock(); - if (pointBufferPosition >= myDrawables->capacity()) { - loopAround = true; - pointBufferPosition = 0; - } - int tempPos = pointBufferPosition * 6; - pointBufferPosition++; - - float atioff = atiCard ? 0.5f : 0.0f; - vertexData[tempPos] = x; - vertexData[tempPos + 1] = y+atioff; - vertexData[tempPos + 2] = color.R; - vertexData[tempPos + 3] = color.G; - vertexData[tempPos + 4] = color.B; - vertexData[tempPos + 5] = color.A; - pointArrayMutex.unlock(); -} - - /*! - * \brief Draws a monocolored series of connected lines. - * \details This function draws Polyline at the given coordinates with the given color. - * \param size The number of vertices of the polyline. - * \param x An array of the x positions of the polyline's vertices. - * \param y An array of the y positions of the polyline's vertices. - * \param color A color for the Polyline. - * \param rotation Rotation of the Polyline in radians clockwise. - */ -void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation) { - Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored series of connected lines. - * \details This function draws Polyline at the given coordinates with the given color. - * \param size The number of vertices of the polyline. - * \param x An array of the x positions of the polyline's vertices. - * \param y An array of the y positions of the polyline's vertices. - * \param color A color array for the Polyline. - * \param rotation Rotation of the Polyline in radians clockwise. - */ -void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation) { - Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a progress bar. - * \details This function draws a previously created ProgressBar to the Canvas, as - * specified in that ProgressBar's constructor. - * \param p A pointer to a ProgressBar. - * \note There is no equivalent function for CartesianCanvas. If you'd like to draw - * a ProgressBar on a CartesianCanvas, you can still use this function, but you must - * use absolute Canvas coordinates rather than the scaled CartesianCanvas coordinates. - */ -void Canvas::drawProgress(ProgressBar* p) { - for (int i = 0; i < p->getSegs(); ++i) { - drawDrawable(p->getRect(i)); - drawDrawable(p->getBorder(i)); - } -} - - /*! - * \brief Draws a monocolored filled or outlined rectangle. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color A single color for Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined rectangle. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color An array of colors for Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with different monocolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A single color for Rectangle's fill vertices. - * \param outlineColor A single color for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with multicolored fill and monocolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for Rectangle's fill vertices. - * \param outlineColor A single color for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with monocolored fill and multicolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A single color for Rectangle's fill vertices. - * \param outlineColor An array of colors for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with different multicolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for Rectangle's fill vertices. - * \param outlineColor An array of colors for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined regular polygon. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param color A single color for RegularPolygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color, bool filled, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a multicolored filled or outlined regular polygon. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and color - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param color An array of colors for RegularPolygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with different monocolored fill and outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor A single color for RegularPolygon's fill vertices. - * \param outlineColor A single color for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with multicolored fill and monocolored outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor An array of colors for RegularPolygon's fill vertices. - * \param outlineColor A single color for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with monocolored fill and multicolored outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor A single color for RegularPolygon's fill vertices. - * \param outlineColor An array of colors for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with different multicolored fill and outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor An array of colors for RegularPolygon's fill vertices. - * \param outlineColor An array of colors for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a monocolored filled or outlined square. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param color A single color for Square. - * \param filled Whether the Square should be filled - * (set to true by default). - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled, float rotation) { - Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined Square. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param color An array of colors for Square. - * \param filled Whether the Square should be filled - * (set to true by default). - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled, float rotation) { - Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with different monocolored fill and outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor A single color for Square's fill vertices. - * \param outlineColor A single color for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with multicolored fill and monocolored outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor An array of colors for Square's fill vertices. - * \param outlineColor A single color for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with monocolored fill and multicolored outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor A single color for Square's fill vertices. - * \param outlineColor An array of colors for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with different multicolored fill and outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor An array of colors for Square's fill vertices. - * \param outlineColor An array of colors for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - - /*! - * \brief Draws a monocolored filled or outlined star. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param color A single color or array of colors for the star vertices. - * \param filled Whether the star should be filled - * (set to true by default). - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color, bool filled, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, color, filled, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a multicolored filled or outlined star. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param color A single color or array of colors for the star vertices. - * \param filled Whether the star should be filled - * (set to true by default). - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color[], bool filled, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, color, filled, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with different monocolored fill and outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with multicolored fill and monocolored outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with monocolored fill and multicolored outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with different multicolored fill and outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \param text The string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \param rotation Rotation of the Text in radians clockwise. - */ -void Canvas::drawText(std::string text, int x, int y, unsigned size, ColorFloat color, std::string fontFileName, float rotation) { - std::wstring wsTmp(text.begin(), text.end()); - std::wstring ws = wsTmp; - drawText(ws, x, y, size, color, fontFileName, rotation); -} - - /*! - * \brief Draws a UTF8-encoded string of text. - * \details This function draws a given string of UTF-8 encoded Text at the given coordinates with the given color. - * \param text The UTF8-encoded string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \param rotation Rotation of the Text in radians clockwise. - * \note Identical to the drawText(std::string, ...) aside from the first parameter. - * \see drawText(std::string s, int x, int y, unsigned size, ColorFloat color = BLACK). - */ -void Canvas::drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color, std::string fontFileName, float rotation) { - Text* t = new Text(text, x, y, size, color); // Creates the Point with the specified coordinates and color - if(fontFileName != defaultFontFileName && fontFileName != "") { - t->setFont(fontFileName); - } else { - if(defaultFontFileName != "") { - t->setFont(defaultFontFileName); - } - } - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined triangle. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color A single color for the Triangle vertices. - * \param filled Whether the Triangle should be filled (set to true by default). - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined triangle. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color An array of colors for the Triangle vertices. - * \param filled Whether the Triangle should be filled (set to true by default). - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with different monocolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A single color for the Triangle's fill vertices. - * \param outlineColor A single color for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with multicolored fill and monocolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill vertices. - * \param outlineColor A single color for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with monocolored fill and multicolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A single color for the Triangle's fill vertices. - * \param outlineColor An array of colors for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with different multicolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill vertices. - * \param outlineColor An array of colors for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled or outlined monocolored triangle strip. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param color A single color for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false). - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled or outlined multicolored triangle strip. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false). - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with different monocolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with multicolored fill and monocolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} +// /*! +// * \brief Draw a string of text. +// * \details This function draws a given string of Text at the given coordinates with the given color. +// * \param text The string to draw. +// * \param x The x coordinate of the text's left bound. +// * \param y The y coordinate of the text's left bound. +// * \param size The size of the text in pixels. +// * \param color The color of the Text (set to BLACK by default). +// * \param rotation Rotation of the Text in radians clockwise. +// */ +// void Canvas::drawText(std::string text, int x, int y, unsigned size, ColorFloat color, std::string fontFileName, float rotation) { +// std::wstring wsTmp(text.begin(), text.end()); +// std::wstring ws = wsTmp; +// drawText(ws, x, y, size, color, fontFileName, rotation); +// } - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with monocolored fill and multicolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer +void Canvas::errorCallback(int error, const char* string) { + fprintf(stderr, "%i: %s\n", error, string); } /*! - * \brief Draws an arbitrary filled and outlined triangle strip with different multicolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. + * \brief Accessor for the current background. + * \return The Background that the Canvas draws when draw() is called. */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - -void Canvas::errorCallback(int error, const char* string) { - fprintf(stderr, "%i: %s\n", error, string); +Background * Canvas::getBackground() { + return myBackground; } /*! @@ -1742,7 +374,7 @@ void Canvas::errorCallback(int error, const char* string) { * \return The color that the Canvas clears to when clear() is called. */ ColorFloat Canvas::getBackgroundColor() { - return bgcolor; + return myBackground->getClearColor(); } /*! @@ -1780,64 +412,20 @@ float Canvas::getFPS() { return realFPS; } - /*! - * \brief Accessor for window's closed status. - * \return Whether the window is still open (that is, the user has not closed it). - */ -bool Canvas::isOpen() { - return !isFinished; -} - /*! * \brief Accessor for the mouse's x-position. * \return The x coordinates of the mouse on the Canvas. */ -int Canvas::getMouseX() { - return mouseX; +float Canvas::getMouseX() { + return mouseX - winWidth/2; } /*! * \brief Accessor for the mouse's y-position. * \return The y coordinates of the mouse on the Canvas. */ -int Canvas::getMouseY() { - return mouseY; -} - - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in row,column format. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas. - * \note getPixel() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param row The row (y-position) of the pixel to grab. - * \param col The column (x-position) of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (col,row). - */ -ColorInt Canvas::getPixel(int row, int col) { - return getPoint(col,row); -} - - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in x,y format. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas. - * \note getPoint() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param x The x position of the pixel to grab. - * \param y The y position of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (x, y). - */ -ColorInt Canvas::getPoint(int x, int y) { - int yy; - //if (atiCard) - // yy = (winHeight) - y; //glReadPixels starts from the bottom left, and we have no way to change that... - //else - yy = (winHeight-1) - y; - int off = 3 * (yy * winWidthPadded + x); - return ColorInt(screenBuffer[off], screenBuffer[off + 1], screenBuffer[off + 2], 255); +float Canvas::getMouseY() { + return (float) winHeight/2 - mouseY; } /*! @@ -1913,18 +501,11 @@ int Canvas::getWindowY() { void Canvas::glDestroy() { // Free up our resources - glDetachShader(shaderProgram, shaderFragment); - glDetachShader(shaderProgram, shaderVertex); - glDeleteShader(shaderFragment); - glDeleteShader(shaderVertex); - glDeleteProgram(shaderProgram); - glDetachShader(textureShaderProgram, textureShaderFragment); - glDetachShader(textureShaderProgram, textureShaderVertex); - glDeleteShader(textureShaderFragment); - glDeleteShader(textureShaderVertex); - glDeleteProgram(textureShaderProgram); - glDeleteBuffers(1, &vertexBuffer); - glDeleteVertexArrays(1, &vertexArray); + delete textShader; + delete shapeShader; + delete textureShader; + glDeleteBuffers(1, &VBO); + glDeleteVertexArrays(1, &VAO); } /*! @@ -1954,71 +535,52 @@ void Canvas::handleIO() { #endif } -void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string title, double timerLength) { +void Canvas::init(int xx, int yy, int ww, int hh, std::string title, ColorFloat backgroundColor, Background * background, double timerLength) { ++openCanvases; if (ww == -1) ww = 1.2*Canvas::getDisplayHeight(); if (hh == -1) hh = 0.75*ww; - b = ww*hh*2; winTitle = title; winWidth = ww, winHeight = hh; - aspect = (float) winWidth / winHeight; + // aspect = (float) winWidth / winHeight; keyDown = false; toClose = false; windowClosed = false; - readyToDraw = false; frameCounter = 0; syncMutexLocked = 0; syncMutexOwner = -1; - int padwidth = winWidth % 4; - if (padwidth > 0) - padwidth = 4-padwidth; - winWidthPadded = winWidth + padwidth; - bufferSize = 3 * (winWidthPadded+1) * winHeight; - proceduralBufferSize = 4 * winWidth * winHeight; - screenBuffer = new uint8_t[bufferSize]; - proceduralBuffer = new GLubyte[proceduralBufferSize]; - for (unsigned i = 0; i < bufferSize; ++i) { - screenBuffer[i] = 0; - } - for (unsigned i = 0; i < proceduralBufferSize; i++) { - proceduralBuffer[i] = 255; - } - started = false; // We haven't started the window yet monitorX = xx; monitorY = yy; - myDrawables = new Array(b); // Initialize myDrawables - drawableBuffer = new Array(b); - // objectBuffer = new Array(b); - vertexData = new float[6 * b]; // Buffer for vertexes for points showFPS = false; // Set debugging FPS to false isFinished = false; // We're not done rendering - pointBufferPosition = pointLastPosition = 0; - loopAround = false; toRecord = 0; - objectBufferEmpty = true; - bgcolor = GRAY; window = nullptr; + defaultBackground = true; + myBackground = nullptr; + drawTimer = new Timer((timerLength > 0.0f) ? timerLength : FRAME); + camera = new Camera(glm::vec3(0.0f, 0.0f, (winHeight / 2) / tan(glm::pi()/6)),glm::vec3(0.0f,1.0f,0.0f),glm::vec3(0.0f,0.0f,0.0f)); for (int i = 0; i <= GLFW_KEY_LAST * 2 + 1; i++) boundKeys[i++] = nullptr; - defaultFontFileName = ""; - + windowMutex.lock(); initGlfw(); #ifndef _WIN32 initWindow(); initGlew(); glfwMakeContextCurrent(NULL); // Reset the context #endif + initGl(); + initBackground(background, backgroundColor); + windowMutex.unlock(); } void Canvas::initGl() { @@ -2031,9 +593,11 @@ void Canvas::initGl() { #endif // Enable and disable necessary stuff - glDisable(GL_DEPTH_TEST); // Disable depth testing because we're not drawing in 3d - glDisable(GL_DITHER); // Disable dithering because pixels do not (generally) overlap - glDisable(GL_CULL_FACE); // Disable culling because the camera is stationary + // glEnable(GL_DEPTH_TEST); // Depth Testing + glDisable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDisable(GL_CULL_FACE); + // glCullFace(GL_BACK); glEnable(GL_BLEND); // Enable blending glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Set blending mode to standard alpha blending @@ -2042,14 +606,6 @@ void Canvas::initGl() { toClose = true; }); - unsigned char stereo[1] = {5}, dbuff[1] = {5}; - int aux[1] = {5}; - glGetBooleanv(GL_STEREO,stereo); - glGetBooleanv(GL_DOUBLEBUFFER,dbuff); - glGetIntegerv(GL_AUX_BUFFERS,aux); - hasStereo = ((int)stereo[0] > 0); - hasBackbuffer = ((int)dbuff[0] > 0); - glfwMakeContextCurrent(NULL); // Reset the context } @@ -2063,17 +619,6 @@ void Canvas::initGlew() { exit(102); } - hasEXTFramebuffer = false; - - GLint n, i; - glGetIntegerv(GL_NUM_EXTENSIONS, &n); - for (i = 0; i < n; i++) { - std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); - if (s == "GL_EXT_framebuffer_object") { - hasEXTFramebuffer = true; - break; - } - } const GLubyte* gfxVendor = glGetString(GL_VENDOR); std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); atiCard = (gfx.find("ATI") != std::string::npos); @@ -2085,93 +630,31 @@ void Canvas::initGlew() { printf("GL Extension: "); for (i = 0; i < n; i++) printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); - if (hasEXTFramebuffer) - TsglDebug("EXT Framebuffer available"); #endif - GLint status; - - // Create and bind our Vertex Array Object - glGenVertexArrays(1, &vertexArray); - glBindVertexArray(vertexArray); - - // Create and bind our Vertex Buffer Object - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - - // Create / compile vertex shader - shaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(shaderVertex, 1, &vertexSource, NULL); - glCompileShader(shaderVertex); - glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile fragment shader - shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(shaderFragment, 1, &fragmentSource, NULL); - glCompileShader(shaderFragment); - glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to a shader program, link the program - shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, shaderVertex); - glAttachShader(shaderProgram, shaderFragment); - glBindFragDataLocation(shaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our standard shader - glLinkProgram(shaderProgram); - - // Create / compile textured vertex shader - textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); - glCompileShader(textureShaderVertex); - glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile textured fragment shader - textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); - glCompileShader(textureShaderFragment); - glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to another shader program, link the program - textureShaderProgram = glCreateProgram(); - glAttachShader(textureShaderProgram, textureShaderVertex); - glAttachShader(textureShaderProgram, textureShaderFragment); - glBindFragDataLocation(textureShaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our textured shader - glLinkProgram(textureShaderProgram); - textureShaders(false); - - /****** NEW ******/ - // Create a framebuffer - frameBuffer = 0; - glGenFramebuffersEXT(1, &frameBuffer); - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); - // The texture we're going to render to - glGenTextures(1, &renderedTexture); - // "Bind" the newly created texture : all future texture functions will modify this texture - glBindTexture(GL_TEXTURE_2D, renderedTexture); - // Give an empty image to OpenGL ( the last "0" ) - // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems - glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // Poor filtering. Needed ! - 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_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // Set "renderedTexture" as our colour attachement #0 - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); - // Set the list of draw buffers. - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - // Always check that our framebuffer is ok - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("FRAMEBUFFER CREATION FAILED"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); + // Create our Vertex Array Object + glGenVertexArrays(1, &VAO); + + // Create our Vertex Buffer Object + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + + textShader = new Shader(textVertexShader, textFragmentShader); + + shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); + + textureShader = new Shader(textureVertexShader, textureFragmentShader); + + // char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ + // char *res = realpath(".", buf); + // if (res) { + // printf("This source is at %s.\n", buf); + // } else { + // perror("realpath"); + // exit(EXIT_FAILURE); + // } } void Canvas::initGlfw() { @@ -2182,6 +665,18 @@ void Canvas::initGlfw() { } } +void Canvas::initBackground(Background * background, ColorFloat bgcolor) { + backgroundMutex.lock(); + if (!background) { + myBackground = new Background(winWidth, winHeight, bgcolor); + } else { + myBackground = background; + background->setClearColor(bgcolor); + } + myBackground->init(shapeShader, textShader, textureShader, camera, window); + backgroundMutex.unlock(); +} + void Canvas::initWindow() { glfwSetErrorCallback(errorCallback); @@ -2192,17 +687,17 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_CLIENT_API,GLFW_OPENGL_ES_API); // Pi uses OpenGL ES #else glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Set target GL major version to 3 - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Set target GL minor version to 3.2 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Set target GL minor version to 3.2 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window + // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer - glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); - glfwMutex.lock(); // GLFW crashes if you try to make more than once window at once + glfwMutex.lock(); // GLFW crashes if you try to make more than one window at once window = glfwCreateWindow(winWidth, winHeight, winTitle.c_str(), NULL, NULL); // Windowed // window = glfwCreateWindow(monInfo->width, monInfo->height, title_.c_str(), glfwGetPrimaryMonitor(), NULL); // Fullscreen if (!window) { @@ -2228,6 +723,34 @@ void Canvas::initWindow() { glfwSetMouseButtonCallback(window, buttonCallback); glfwSetKeyCallback(window, keyCallback); glfwSetScrollCallback(window, scrollCallback); + + // Scale to window size + GLint windowWidth, windowHeight; + glfwGetWindowSize(window, &windowWidth, &windowHeight); + glViewport(0, 0, windowWidth, windowHeight); + winWidth = windowWidth; + winHeight = windowHeight; + + glfwGetFramebufferSize(window, &framebufferWidth, &framebufferHeight); + + screenBufferMutex.lock(); + screenBuffer = new uint8_t[3 * (framebufferWidth) * framebufferHeight]; + for (int i = 0; i < 3 * (framebufferWidth) * framebufferHeight; ++i) { + screenBuffer[i] = 0; + } + screenBufferMutex.unlock(); + + // Get info of GPU and supported OpenGL version + // printf("Renderer: %s\n", glGetString(GL_RENDERER)); + // printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); +} + + /*! + * \brief Accessor for window's closed status. + * \return Whether the window is still open (that is, the user has not closed it). + */ +bool Canvas::isOpen() { + return !isFinished; } void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { @@ -2247,14 +770,14 @@ void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, void Canvas::pauseDrawing() { #pragma omp critical (pauseResume) { - if (syncMutexLocked == 0 && syncMutexOwner == -1) { - syncMutex.lock(); - syncMutexOwner = omp_get_thread_num(); - } - #pragma omp critical (syncMutLock) - { - ++syncMutexLocked; - } + if (syncMutexLocked == 0 && syncMutexOwner == -1) { + syncMutex.lock(); + syncMutexOwner = omp_get_thread_num(); + } + #pragma omp critical (syncMutLock) + { + ++syncMutexLocked; + } } } @@ -2350,6 +873,18 @@ void Canvas::run(void (*myFunction)(Canvas&, int, int), int i1, int i2) { start(); myFunction(*this, i1, i2); wait(); } + /*! + * \brief Overload for run() + * \param myFunction The function to run on the Canvas. Must take exactly one parameter of type Canvas&, + * which is a reference to the Canvas to render to. + * \param i1 An integer argument to myFunction + * \param i2 An integer argument to myFunction + * \param i3 An integer argument to myFunction + */ +void Canvas::run(void (*myFunction)(Canvas&, int, int, int), int i1, int i2, int i3) { + start(); myFunction(*this, i1, i2, i3); wait(); +} + /*! * \brief Overload for run() * \param myFunction The function to run on the Canvas. Must take exactly one parameter of type Canvas&, @@ -2405,11 +940,27 @@ void Canvas::run(void (*myFunction)(Canvas&, int, std::string, bool), int i, std start(); myFunction(*this, i, s, b); wait(); } +void Canvas::run(void (*myFunction)(Canvas&, int, char**), int argc, char* argv[]) { + start(); myFunction(*this, argc, argv); wait(); +} + void Canvas::screenShot() { char filename[25]; sprintf(filename, "Image%06d.png", frameCounter); // TODO: Make this save somewhere not in root - loader.saveImageToFile(filename, screenBuffer, winWidthPadded, winHeight); + screenBufferMutex.lock(); + // loader.saveImageToFile(filename, screenBuffer, framebufferWidth, winHeight); + for (int j = 0; j < framebufferHeight - (framebufferHeight / 2); j++) { + for (int i = 0; i < 3 * framebufferWidth; i++) { + int s1 = 3 * framebufferWidth * j + i; + int s2 = 3 * framebufferWidth * (framebufferHeight - 1 - j) + i; // This needs to be height *MINUS ONE* minus j + char tmp = screenBuffer[s1]; + screenBuffer[s1] = screenBuffer[s2]; + screenBuffer[s2] = tmp; + } + } + stbi_write_png(filename, framebufferWidth, framebufferHeight, 3, screenBuffer, 0); + screenBufferMutex.unlock(); } void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { @@ -2417,6 +968,26 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { if (can->scrollFunction) can->scrollFunction(xpos, ypos); } + /*! + * \brief Mutator for the Canvas Background. + * \details This function sets the Background which Canvas will draw. + * \param background A pointer to the new Background value which will be assigned to myBackground. + * \param previouslySet Boolean indicating if background has been previously set for this Canvas. + */ +void Canvas::setBackground(Background * background, bool previouslySet) { + backgroundMutex.lock(); + if (myBackground != background) { + defaultBackground = false; + myBackground = background; + if (!previouslySet) { + windowMutex.lock(); + background->init(shapeShader, textShader, textureShader, camera, window); + windowMutex.unlock(); + } + } + backgroundMutex.unlock(); +} + /*! * \brief Mutator for the background color. * \details This function sets the clear color for when Canvas::clear() is called. @@ -2424,27 +995,15 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { * \note The alpha channel of the color is ignored. */ void Canvas::setBackgroundColor(ColorFloat color) { - bgcolor = color; + windowMutex.lock(); if (window != nullptr) { glfwMakeContextCurrent(window); - glClearColor(color.R,color.G,color.B,color.A); + backgroundMutex.lock(); + myBackground->setClearColor(color); + backgroundMutex.unlock(); glfwMakeContextCurrent(NULL); } -} - -void Canvas::setDrawBuffer(int buffer) { - Canvas::drawBuffer = buffer; -} - - /*! - * \brief Mutator for the currently loaded font. - * \details This function sets the font with the specified filename into memory. - * Subsequent calls to drawText() will use this font to print. - * \param filename The filename of the font to load. - * \note Supports all font types that FreeType supports. - */ -void Canvas::setFont(std::string filename) { - defaultFontFileName = filename; + windowMutex.unlock(); } /*! @@ -2455,24 +1014,6 @@ void Canvas::setShowFPS(bool b) { showFPS = b; } -void Canvas::setupCamera() { - // Set up camera positioning - // Note: (winWidth-1) is a dark voodoo magic fix for some camera issues - float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, - -(winWidth-1) / 2.0f, (winHeight) / 2.0f, -(winHeight) / 2.0f, 1 }; -// float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, -// -(winWidth-1) / 2.0f, (winHeight+0.5f) / 2.0f, -(winHeight-0.5f) / 2.0f, 1 }; - glUniformMatrix4fv(uniView, 1, GL_FALSE, &viewF[0]); - - // Set up camera zooming - float projF[] = { 1.0f / aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1.0f, -1, 0, 0, -0.02f, 0 }; - glUniformMatrix4fv(uniProj, 1, GL_FALSE, &projF[0]); - - // Set up camera transformation - float modelF[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; - glUniformMatrix4fv(uniModel, 1, GL_FALSE, &modelF[0]); -} - /*! * \brief Sleeps the calling thread to sync with the Canvas. * \details Tells the calling thread to sleep until the Canvas' drawTimer expires. @@ -2520,14 +1061,12 @@ int Canvas::start() { #ifdef __APPLE__ void* Canvas::startDrawing(void* cPtr) { Canvas* c = (Canvas*)cPtr; - c->initGl(); c->draw(); c->isFinished = true; pthread_exit(NULL); } #else void Canvas::startDrawing(Canvas *c) { - c->initGl(); c->draw(); c->isFinished = true; glfwDestroyWindow(c->window); @@ -2564,46 +1103,56 @@ void Canvas::takeScreenShot() { if (toRecord == 0) toRecord = 1; } -void Canvas::textureShaders(bool on) { - GLint program; - if (!on) { - program = shaderProgram; - - // Relocate the shader attributes - GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); +void Canvas::selectShaders(unsigned int sType) { + Shader * program = 0; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + GLint aspectLoc = glGetUniformLocation(textShader->ID, "aspect"); + glUniformMatrix4fv(aspectLoc, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 0); - GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); glEnableVertexAttribArray(colAttrib); - glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) (2 * sizeof(float))); - - } else { - program = textureShaderProgram; - - // Relocate the shader attributes - GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); - glEnableVertexAttribArray(texturePosAttrib); - glVertexAttribPointer(texturePosAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); - GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); - glEnableVertexAttribArray(textureColAttrib); - glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), - (void*) (2 * sizeof(float))); - GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); - glEnableVertexAttribArray(textureTexAttrib); - glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), - (void*) (6 * sizeof(float))); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); } - - // Reallocate the shader program for use - glUseProgram(program); - + // Recompute the camera matrices - uniModel = glGetUniformLocation(program, "model"); - uniView = glGetUniformLocation(program, "view"); - uniProj = glGetUniformLocation(program, "proj"); + uniModel = glGetUniformLocation(program->ID, "model"); + uniView = glGetUniformLocation(program->ID, "view"); + uniProj = glGetUniformLocation(program->ID, "projection"); + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)winWidth/(float)winHeight, 0.1f, 5000.0f); + glm::mat4 view = camera->getViewMatrix(); + glm::mat4 model = glm::mat4(1.0f); - // Update the camera - setupCamera(); + glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(uniView, 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model)); } /*! @@ -2625,278 +1174,4 @@ int Canvas::wait() { return 0; } - -//-----------------Unit testing------------------------------------------------------- - /*! - * \brief Runs unit tests for the Canvas. - */ -void Canvas::runTests() { - TsglDebug("Testing Canvas class..."); - Canvas c1(0, 0, 500, 500, "", FRAME); - c1.setBackgroundColor(WHITE); - c1.start(); - tsglAssert(testFilledDraw(c1), "Unit test for filled draw failed!"); - tsglAssert(testLine(c1), "Unit test for line failed!"); - // tsglAssert(testAccessors(c1), "Unit test for accessors failed!"); - tsglAssert(testDrawImage(c1), "Unit test for drawing images failed!"); - c1.stop(); - TsglDebug("Unit tests for Canvas complete."); - std::cout << std::endl; -} - -//Similar format is used for the remaining unit tests -bool Canvas::testFilledDraw(Canvas& can) { - int passed = 0; //Passed tests - int failed = 0; //Failed tests - ColorInt red(255, 0, 0); //Fill color - can.drawCircle(250, 250, 50, red, true); //Draw filled shape - can.sleepFor(1); - - //Test 1: Get middle pixel and see if its red. - if(can.getPixel(250, 250) == red) { - passed++; - } else { - failed++; - TsglErr("Test 1, middle pixel for testFilledDraw() failed!"); - } - - //Test 2: Get leftmost and rightmost pixel of the circle - //Have to add or subtract 1 from the y so that you can get the correct pixel (center radius is 1. No 0 radius). - if(can.getPixel(250, 201) == red && can.getPixel(250, 299) == red) { - passed++; - } else { - failed++; - TsglErr("Test 2, leftmost and rightmost pixel for testFilledDraw() failed!"); - } - - //Test 3: Outside pixels shouldn't equal inside pixels - int test = 0; - //Single pixel.... - if(can.getPixel(1, 1) != red) { - //Multiple pixels.... - for(int i = 201; i <= 299; i++) { - if(can.getPixel(1, i) != red) { - test++; - } - } - //Results of multiple pixels... - if(test == 99) { - passed++; - } else { - failed++; - TsglErr("Test 3, outside != inside, Multiple pixels for testFilledDraw() failed!"); - } - } else { - failed++; - TsglErr("Test 3, outside != inside, Single pixel for testFilledDraw() failed!"); - } - - //Test 4: A LOT of the pixels on the inside should be red - int count = 0; - for(int i = 201; i <= 299; i++) { - if(can.getPixel(250, i) == red) { - count++; - } - } - - //Now check the count, should be 99 - if(count == 99) { - passed++; - } else { - failed++; - std::cout << "Count: " << count << std::endl; - TsglErr("Test 4, multiple pixels for testFilledDraw() failed!"); - } - - //Determine if we passed all four tests or not, Results: - if(passed == 4 && failed == 0) { - can.clearProcedural(); - TsglDebug("Unit test for drawing filled shapes passed!"); - return true; - } else { - can.clearProcedural(); - TsglErr("This many passed for testFilledDraw(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testFilledDraw(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -bool Canvas::testLine(Canvas & can) { - int passed = 0; - int failed = 0; - can.drawLine(0, 0, 250, 250, BLACK); //Diagonal line - can.drawLine(253, 253, 400, 253); //Straight line - can.sleepFor(1); - ColorInt black(0, 0, 0); - //Test 1: Near the ending endpoint? (Diagonal) - if(can.getPoint(249, 249) == black) { - passed++; - } else { - failed++; - TsglErr("Test 1, Near the ending endpoint? for testLine() failed!"); - } - - //Test 2: Somewhere in the middle? (Diagonal) - if(can.getPoint(155, 155) == black) { - passed++; - } else { - failed++; - TsglErr("Test 2, Somewhere in the middle? for testLine() failed!"); - } - - //Test 3: Near the starting endpoint? (Diagonal) - if(can.getPoint(15, 15) == black) { - passed++; - } else { - failed++; - TsglErr("Test 3, Near the starting endpoint? for testLine() failed!"); - } - - //Test 4: An entire line? (Straight) - int count = 0; - for(int i = 253; i <= 399; i++) { - if(can.getPoint(i, 253) == black) { - count++; - } - } - - //Check the results of the Straight line test - if(count == 147) { - passed++; - } else { - failed++; - TsglErr("Test 4, An entire line? (Straight) for testLine() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - can.clearProcedural(); - TsglDebug("Unit test for line passed!"); - return true; - } else { - can.clearProcedural(); - TsglErr("This many passed testLine(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testLine(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -bool Canvas::testAccessors(Canvas& can) { - int passed = 0; - int failed = 0; - ColorFloat white = WHITE; //Have to set these to new variables so that I can compare them - ColorFloat black = BLACK; - - //Test 1: Background color - if(can.getBackgroundColor() == white) { - can.setBackgroundColor(BLACK); - if(can.getBackgroundColor() == black) { - passed++; - } else { - failed++; - TsglErr("Test 1, Background color for testAccessors() failed!"); - } - } - - //Test 2: Window width/height - //width - if(can.getWindowWidth() == 500) { - //height - if(can.getWindowHeight() == 500) { - passed++; - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (height)"); - } - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (width)"); - } - - //Test 3: Window x/y - //x - if(can.getWindowX() == 0) { - //y - if(can.getWindowY() == 0) { - passed++; - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (y)"); - } - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (x)"); - } - - //Test 4: Window open? - if(can.isOpen() == true) { - passed++; - } else { - failed++; - TsglErr("Test 4, Window open? for testAccessors() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - can.clearProcedural(); - TsglDebug("Unit test for accessors/mutators passed!"); - return true; - } else { - can.clearProcedural(); - TsglErr("This many passed for testAccessors(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testAccessors(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -bool Canvas::testDrawImage(Canvas& can) { - can.drawImage("../assets/pics/ff0000.png", 0, 0, 200, 200); - can.sleepFor(1); - int passed = 0; - int failed = 0; - ColorInt red(255, 0, 0); - //Test 1: Single pixel - if(can.getPoint(1, 1) == red) { - passed++; - } else { - failed++; - TsglErr("Test 1, Single pixel for testDrawImage() failed!"); - } - - //Test 2: Multiple pixels - int count = 0; - for(int i = 0; i < 200; i++) { - if(can.getPoint(1, i) == red) { - count++; - } - } - - //Results of Test 2: - if(count == 200) { - passed++; - } else { - failed++; - std::cout << "Count: " << count << std::endl; - TsglErr("Test 2, Multiple pixels for testDrawImage() failed!"); - } - - //Results of entire Unit test:s - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for drawing images passed!"); - return true; - } else { - TsglErr("This many passed for testDrawImage(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testDrawImage(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} -//------------End Unit testing-------------------------------------------------------- } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 3ca778b2f..a4fb35a36 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -12,9 +12,16 @@ #include "Array.h" // Our own array for buffering drawing operations #include "Arrow.h" // Our own array for drawing arrows +#include "Background.h" // Our own class for drawing a background +#include "CartesianBackground.h" // Our own class for drawing a cartesian background #include "Color.h" // Our own interface for converting color types +#include "Cone.h" // Our own class for drawing cones +#include "Cube.h" // Our own class for drawing cubes +#include "Cuboid.h" // Our own class for drawing cuboids +#include "Cylinder.h" // Our own class for drawing cylinders #include "TriangleStrip.h" // Our own class for drawing polygons with colored vertices #include "Ellipse.h" // Our own class for drawing ellipses +#include "Ellipsoid.h" // Our own class for drawing ellipsoids #include "Circle.h" // Our own class for drawing circles #include "ConcavePolygon.h" // Our own class for concave polygons with colored vertices #include "ConvexPolygon.h" // Our own class for convex polygons with colored vertices @@ -23,8 +30,10 @@ #include "Line.h" // Our own class for drawing straight lines #include "Polyline.h" // Our own class for drawing polylines #include "ProgressBar.h" // Our own class for drawing progress bars +#include "Pyramid.h" // Our own class for drawing pyramids #include "Rectangle.h" // Our own class for drawing rectangles #include "RegularPolygon.h" // Our own class for drawing regular polygons +#include "Sphere.h" // Our own class for drawing spheres #include "Square.h" // Our own class for drawing squares #include "Star.h" // Our own class for drawing stars #include "Text.h" // Our own class for drawing text @@ -32,20 +41,30 @@ #include "Triangle.h" // Our own class for drawing triangles #include "Util.h" // Needed constants and has cmath for performing math operations +#include "Camera.h" +#include "Shader.h" +#include +#include +#include + +#include +#include +#include + #include // For callback upon key presses #include // DEBUGGING #include // Needed for locking the Canvas for thread-safety #include // For string building #include // For window titles #include +#include #ifdef __APPLE__ #include #else #include // For spawning rendering in a different thread #endif -#include // Needed for GL function calls -#include // For window creation and management +#include "gl_includes.h" #ifdef _WIN32 #define round(x) ((x-floor(x))>0.5 ? ceil(x) : floor(x)) // round is not defined in Visual Studio @@ -67,77 +86,59 @@ namespace tsgl { * \bug Linux: X forwarding does not work properly with TSGL. */ class Canvas { -private: +protected: typedef GLFWvidmode const* displayInfo; typedef std::function doubleFunction; typedef std::function voidFunction; - float aspect; // Aspect ratio used for setting up the window - ColorFloat bgcolor; // Color of the Canvas' clearRectangle + // float aspect; // Aspect ratio used for setting up the window + bool atiCard; // Whether the vendor of the graphics card is ATI + std::mutex backgroundMutex; // Mutex for myBackground voidFunction boundKeys [(GLFW_KEY_LAST+1)*2]; // Array of function objects for key binding - std::mutex bufferMutex; // Mutex for locking the render buffer so that only one thread can read/write at a time - unsigned bufferSize; // Size of the screen buffer - std::string defaultFontFileName; + Camera* camera; + bool defaultBackground; // Boolean indicating whether myBackground has been set by an external source Timer* drawTimer; // Timer to regulate drawing frequency - GLuint frameBuffer; // Target buffer for rendering to renderedTexture + GLint framebufferWidth; + GLint framebufferHeight; int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) - bool hasBackbuffer; // Whether or not the hardware supports double-buffering - bool hasEXTFramebuffer; // Whether or not the hard supports EXT FBOs - bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice - TextureHandler loader; // The ImageLoader that holds all our already loaded textures - bool loopAround; // Whether our point buffer has looped back to the beginning this int monitorX, monitorY; // Monitor position for upper left corner double mouseX, mouseY; // Location of the mouse once HandleIO() has been called - Array * myDrawables; // Our buffer of drawables to draw - std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame - bool objectBufferEmpty; // States whether the object buffer is empty/has been recently cleared + Background * myBackground; // Pointer to the Background drawn each frame + std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame std::mutex objectMutex; - Array * drawableBuffer; // Our buffer of drawables that the can be pushed to, and will later be flushed to the shapes array - std::mutex pointArrayMutex; // Mutex for the allPoints array - unsigned int pointBufferPosition, pointLastPosition; // Holds the position of the allPoints array - bool readyToDraw; // Whether a Canvas is ready to start drawing int realFPS; // Actual FPS of drawing - GLuint renderedTexture; // Texture to which we render to every frame #ifdef __APPLE__ pthread_t renderThread; // Thread dedicated to rendering the Canvas #else std::thread renderThread; // Thread dedicated to rendering the Canvas #endif uint8_t* screenBuffer; // Array that is a copy of the screen - GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window - unsigned proceduralBufferSize; + std::mutex screenBufferMutex; // mutex for the screenbuffer doubleFunction scrollFunction; // Single function object for scrolling - GLtexture shaderFragment, // Address of the fragment shader - shaderProgram, // Addres of the shader program to send to the GPU - shaderVertex; // Address of the vertex shader - std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time + Shader * textShader; // Shader for Text class + Shader * shapeShader; // Shader for Shape class + Shader * textureShader; // Shader for Background and Image classes bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread int syncMutexLocked; // Whether the syncMutex is currently locked int syncMutexOwner; // Thread ID of the owner of the syncMutex - GLtexture textureShaderFragment, // Address of the textured fragment shader - textureShaderProgram, // Addres of the textured shader program to send to the GPU - textureShaderVertex; // Address of the textured vertex shader bool toClose; // If the Canvas has been asked to close unsigned int toRecord; // To record the screen each frame GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - GLtexture vertexArray, // Address of GL's array buffer object - vertexBuffer; // Address of GL's vertex buffer object - float* vertexData; // The allPoints array + GLuint VAO, // Address of GL's vertex array object + VBO; // Address of GL's vertex buffer object GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not std::mutex windowMutex; // (OS X) Mutex for handling window contexts int winHeight; // Height of the Canvas' window std::string winTitle; // Title of the window - int winWidth; // Width of the Canvas' window - int winWidthPadded; // Window width padded to a multiple of 4 (necessary for taking screenshots) + GLint winWidth; // Width of the Canvas' window - static int drawBuffer; // Buffer to use for drawing (set to GL_LEFT or GL_RIGHT) static bool glfwIsReady; // Whether or not we have info about our monitor static std::mutex glfwMutex; // Keeps GLFW createWindow from getting called at the same time in multiple threads static displayInfo monInfo; // Info about our display @@ -149,8 +150,11 @@ class Canvas { static void errorCallback(int error, const char* string); // Display where an error is coming from void glDestroy(); // Destroys the GL and GLFW things that are specific for this canvas void init(int xx,int yy,int ww,int hh, - unsigned int b, std::string title, + std::string title, + ColorFloat backgroundColor, Background * background, double timerLength); // Method for initializing the canvas + void initBackground(Background * background, + ColorFloat bgcolor); // Initializes myBackground void initGl(); // Initializes the GL things specific to the Canvas void initGlew(); // Initialized the GLEW things specific to the Canvas static void initGlfw(); // Initalizes GLFW for all future canvases. @@ -161,26 +165,17 @@ class Canvas { static void scrollCallback(GLFWwindow* window, double xpos, double ypos); // GLFW callback for scrolling static void setDrawBuffer(int buffer); // Sets the buffer used for drawing - void setupCamera(); // Setup the 2D camera for smooth rendering #ifdef __APPLE__ static void* startDrawing(void* cPtr); #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void textureShaders(bool state); // Turn textures on or off - static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works - static bool testLine(Canvas& can); // Unit tester for lines - static bool testAccessors(Canvas& can); // Unit tester for accessor methods - static bool testDrawImage(Canvas& can); // Unit tester for drawing images (simultaneously a Unit test for Image) - -protected: - bool atiCard; // Whether the vendor of the graphics card is ATI - void drawDrawable(Drawable* s); // Draw a drawable type + virtual void selectShaders(unsigned int choice); // Select appropriate shader for type of Drawable public: - Canvas(double timerLength = 0.0f); + Canvas(double timerLength = 0.0f, Background * background = nullptr); - Canvas(int x, int y, int width, int height, std::string title, double timerLength = 0.0f); + Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor = GRAY, Background * background = nullptr, double timerLength = 0.0f); virtual ~Canvas(); @@ -188,162 +183,20 @@ class Canvas { void bindToScroll(std::function function); - void clearProcedural(); - - void close(); - void add(Drawable * shapePtr); - void remove(Drawable * shapePtr); - - void clearObjectBuffer(bool shouldFreeMemory = false); - - virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow = false); - - virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow = false); - - virtual void drawCircle(int x, int y, int radius, ColorFloat color, bool filled = true); - - virtual void drawCircle(int x, int y, int radius, ColorFloat color[], bool filled = true); - - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor); - - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor); - - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]); - - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawImage(std::string filename, int x, int y, int width, int height, float alpha = 1.0f, float rotation = 0); - - virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color = BLACK, float rotation = 0); - - virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation = 0); - - virtual void drawPixel(int row, int col, ColorFloat color = BLACK); - - virtual void drawPoint(int x, int y, ColorFloat color = BLACK); - - virtual void drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation = 0); - - virtual void drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation = 0); - - virtual void drawProgress(ProgressBar* p); - - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled = true, float rotation = 0); + void clearBackground(); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color = BLACK, bool filled = true, float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color, bool filled = true, bool ninja = false, float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color[], bool filled = true, bool ninja = false, float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - virtual void drawText(std::string text, int x, int y, unsigned size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - virtual void drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + void close(); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + void clearObjectBuffer(bool shouldFreeMemory = false); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + virtual Background * getBackground(); ColorFloat getBackgroundColor(); + Camera * getCamera() { return camera; } + static int getDisplayHeight(); static int getDisplayWidth(); @@ -352,15 +205,9 @@ class Canvas { float getFPS(); - bool isOpen(); - - int getMouseX(); - - int getMouseY(); + virtual float getMouseX(); - ColorInt getPixel(int row, int col); - - ColorInt getPoint(int x, int y); + virtual float getMouseY(); unsigned int getReps() const; @@ -380,10 +227,14 @@ class Canvas { void handleIO(); + bool isOpen(); + void pauseDrawing(); void recordForNumFrames(unsigned int num_frames); + void remove(Drawable * shapePtr); + void reset(); void resumeDrawing(); @@ -395,6 +246,8 @@ class Canvas { virtual void run(void (*myFunction)(Canvas&, unsigned), unsigned u); virtual void run(void (*myFunction)(Canvas&, int, int), int i1, int i2); + + virtual void run(void (*myFunction)(Canvas&, int, int, int), int i1, int i2, int i3); virtual void run(void (*myFunction)(Canvas&, unsigned, unsigned), unsigned u1, unsigned u2); @@ -406,6 +259,10 @@ class Canvas { virtual void run(void (*myFunction)(Canvas&, int, std::string, bool), int i, std::string s, bool b); + virtual void run(void (*myFunction)(Canvas&, int, char**), int argc, char* argv[]); + + void setBackground(Background * background, bool previouslySet = false); + void setBackgroundColor(ColorFloat color); void setFont(std::string filename); @@ -425,8 +282,6 @@ class Canvas { void takeScreenShot(); int wait(); - - static void runTests(); }; } diff --git a/src/TSGL/CartesianBackground.cpp b/src/TSGL/CartesianBackground.cpp new file mode 100644 index 000000000..f3113f742 --- /dev/null +++ b/src/TSGL/CartesianBackground.cpp @@ -0,0 +1,377 @@ +#include "CartesianBackground.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new CartesianBackground. + * \details Creates a Background whose world dimensions don't have to match its pixel dimensions. + * \param width CartesianBackground's width in pixels. + * \param height CartesianBackground's height in pixels. + * \param xMin x value of the left side of the CartesianBackground in world coordinates. + * \param xMax x value of the right side of the CartesianBackground in world coordinates. + * \param yMin y value of the bottom side of the CartesianBackground in world coordinates. + * \param yMax y value of the top side of the CartesianBackground in world coordinates. + * \param c A ColorFloat for the CartesianBackground's original color. + * \warning An invariant is held where if xMax or xMin isn't greater than its respective min then an error message is given. + * \return A new CartesianBackground to which Drawables and Pixels can be drawn procedurally. + */ +CartesianBackground::CartesianBackground(GLint width, GLint height, Decimal xMin, Decimal yMin, Decimal xMax, Decimal yMax, const ColorFloat &clearColor) : Background(width, height, clearColor) +{ + if (xMax < xMin || yMax < yMin) { + TsglErr("Maximum values must be greater than minimum values."); + return; + } + attribMutex.lock(); + myXMin = xMin; + myXMax = xMax; + myYMin = yMin; + myYMax = yMax; + myCartWidth = xMax - xMin; + myCartHeight = yMax - yMin; + pixelWidth = myCartWidth / (myWidth - 1); + pixelHeight = myCartHeight / (myHeight - 1); //Minor hacky fix + vertices[0] = vertices[11] = vertices[21] = vertices[10] = vertices[26] = vertices[20] = -0.5 * ((myCartHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myCartHeight / 2) / tan(glm::pi()/6)); // x + y + vertices[5] = vertices[1] = vertices[15] = vertices[6] = vertices[25] = vertices[16] = 0.5 * ((myCartHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myCartHeight / 2) / tan(glm::pi()/6)); // x + y + attribMutex.unlock(); +} + + /*! + * \brief Draw the CartesianBackground. + * \details This function actually draws the CartesianBackground to the Canvas. + * \note On each draw cycle, first any Drawables that have been newly added to the CartesianBackground will be rendered, and then any new calls to drawPixel will be processed. + */ +void CartesianBackground::draw() { + if (!complete) { + TsglDebug("Shaders have not been defined for this background."); + return; + } + + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + glEnable(GL_DEPTH_TEST); + + if (toClear) { + attribMutex.lock(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + toClear = false; + attribMutex.unlock(); + } + + glViewport(0,0,myWidth,myHeight); + + drawableMutex.lock(); + for (unsigned int i = 0; i < myDrawables->size(); i++) + { + Drawable* d = (*myDrawables)[i]; + if(d->isProcessed()) { + selectShaders(d->getShaderType()); + if (d->getShaderType() == SHAPE_SHADER_TYPE) { + d->draw(shapeShader); + } else if (d->getShaderType() == TEXTURE_SHADER_TYPE) { + d->draw(textureShader); + } else if (d->getShaderType() == TEXT_SHADER_TYPE) { + d->draw(textShader); + } + } + } + myDrawables->clear(); + drawableMutex.unlock(); + + // setting up texture shaders for both pixel drawing and post-blit render + selectShaders(TEXTURE_SHADER_TYPE); + + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3((float) (myXMax + myXMin) / 2, (float) (myYMax + myYMin) / 2, 0)); + model = glm::scale(model, glm::vec3((float)myCartWidth, (float)myCartHeight, 1)); + + unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + + glClear(GL_DEPTH_BUFFER_BIT); + + // check for new pixels being drawn + pixelBufferMutex.lock(); + if (newPixelsDrawn) { + glBindTexture(GL_TEXTURE_2D, pixelTexture); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixelTextureBuffer); + glGenerateMipmap(GL_TEXTURE_2D); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + newPixelsDrawn = false; + } + pixelBufferMutex.unlock(); + + // blit MSAA framebuffer to non-MSAA framebuffer's texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, myWidth, myHeight, 0, 0, myWidth, myHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0,0,framebufferWidth,framebufferHeight); + + glDisable(GL_DEPTH_TEST); + + model = glm::mat4(1.0f); + model = glm::scale(model, glm::vec3((float)myCartWidth, (float)myCartHeight, 1)); + + modelLoc = glGetUniformLocation(textureShader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glm::mat4 view = glm::mat4(1.0f); + view = glm::translate(view, glm::vec3(0, 0, (((float)myCartHeight / 2) / tan(glm::pi()/6)))); + + glUniformMatrix4fv(glGetUniformLocation(textureShader->ID, "view"), 1, GL_FALSE, &view[0][0]); + + glBindTexture(GL_TEXTURE_2D,intermediateTexture); + + // read pixels into buffer for Background::getPixel() + readPixelMutex.lock(); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, readPixelBuffer); + readPixelMutex.unlock(); + + // render non-MSAA framebuffer's texture to default framebuffer + glPixelStorei(GL_UNPACK_ALIGNMENT,4); + 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_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + /* next two lines are very essential */ + glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES,0,6); + glEnable(GL_DEPTH_TEST); +} + + /*! + * \brief Draws axes on the Cartesian Background. + * \details This function draws axes (with tick marks) on the CartesianBackground, centered at the + * given (Cartesian) coordinates + * \param originX The horizontal location of the y-axis line. + * \param originY The vertical location of the x-axis line. + * \param spacingX The distance between marks on the x-axis. + * \param spacingY The distance between marks on the y-axis. + */ +void CartesianBackground::drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY) { + drawLine(myXMax, originY, 0, myXMin, originY, 0, 0,0,0, BLACK); // Make the two axes + drawLine(originX, myYMax, 0, originX, myYMin, 0, 0,0,0, BLACK); + + if (spacingX != 0.0) { + if (spacingX < 0.0) spacingX = -spacingX; + + for (Decimal x_ = originX + spacingX; x_ < myXMax; x_ += spacingX) { + drawLine(x_, originY + 8 * pixelHeight, 0, x_, originY - 8 * pixelHeight, 0, 0,0,0, BLACK); + } + for (Decimal x_ = originX - spacingX; x_ > myXMin; x_ -= spacingX) { + drawLine(x_, originY + 8 * pixelHeight, 0, x_, originY - 8 * pixelHeight, 0, 0,0,0, BLACK); + } + } + if (spacingY != 0.0) { + if (spacingY < 0.0) spacingY = -spacingY; + + for (Decimal y_ = originY + spacingY; y_ < myYMax; y_ += spacingY) { + drawLine(originX + 8 * pixelWidth, y_, 0, originX - 8 * pixelWidth, y_, 0, 0,0,0, BLACK); + } + for (Decimal y_ = originY - spacingY; y_ > myYMin; y_ -= spacingY) { + drawLine(originX + 8 * pixelWidth, y_, 0, originX - 8 * pixelWidth, y_, 0, 0,0,0, BLACK); + } + } +} + + /*! + * \brief Plots a function on the screen. + * \details This function receives a TSGL Function instance as a parameter and plots the function on the CartesianCanvas. + * \param function Reference to the Function to plot. + * \param color The color of the vertices of the plotted function (set to BLACK by default). + */ +void CartesianBackground::drawFunction(const Function &function, ColorFloat color) { + int index = 0; + int values = (int) ceil((myXMax - myXMin) / pixelWidth); + float vertices[values*3]; + Decimal y; + for (Decimal x = myXMin; x < myXMax; x += pixelWidth) { + y = function.valueAt(x); + vertices[index] = x; + vertices[index+1] = y; + vertices[index+2] = 0; + index += 3; + } + drawPolyline(0,0,0,values,vertices,0,0,0,color); +} + + /*! + * \brief Plots a function on the screen. + * \details This function receives a pointer to a function method as a parameter and plots the function on + * the CartesianCanvas. + * \param function Pointer to the function-drawing method to plot. + * \param color The color of the vertices of the plotted function (set to BLACK by default). + * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. + */ +void CartesianBackground::drawFunction(functionPointer &function, ColorFloat color) { + drawPartialFunction(function,myXMin,myXMax,color); +} + + /*! + * \brief Plots part of a function on the screen. + * \details This function receives a pointer to a function method as a parameter and plots the function on + * the CartesianCanvas between the specified minimum and maximum coordinates. + * \param function Pointer to the function-drawing method to plot. + * \param min Minimum x value to evaluate and plot + * \param max Maximum x value to evaluate and plot + * \param color The color of the vertices of the plotted function (set to BLACK by default). + * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. + */ +void CartesianBackground::drawPartialFunction(functionPointer &function, Decimal min, Decimal max, ColorFloat color) { + int index = 0; + int values = (int) ceil((max - min) / pixelWidth); + float vertices[values*3]; + Decimal y; + for (Decimal x = min; x < max; x += pixelWidth) { + y = (function)(x); + vertices[index] = x; + vertices[index+1] = y; + vertices[index+2] = 0; + index += 3; + } + drawPolyline(0,0,0,values,vertices,0,0,0,color); +} + + /*! + * \brief Draws a single pixel, specified in x,y format, at the given Cartesian coordinates. + * \details This function alters the value at the specified x, y offset within the Background's buffer variable. + * \note x and y must be given in world (Cartesian coordinates). + * \param x The Cartesian x-position of the pixel. + * \param y The Cartesian y-position of the pixel. + * \param color The color of the point. + */ +void CartesianBackground::drawPixel(float x, float y, ColorInt c) { + attribMutex.lock(); + float screenX = (x - myXMin - myCartWidth/2) * myWidth / myCartWidth; + float screenY = (y - myYMin - myCartHeight/2) * myHeight / myCartHeight; + attribMutex.unlock(); + Background::drawPixel(screenX, screenY, c); +} + + /*! + * \brief Gets the color of the pixel drawn on the current Background at the given x and y Cartesian coordinates. + * \note x and y must be given in world (Cartesian coordinates). + * \param x The Cartesian x-position of the pixel to grab. + * \param y The Cartesian y-position of the pixel to grab. + * \return A ColorInt containing the color of the pixel at (x,y). + */ +ColorInt CartesianBackground::getPixel(float x, float y) { + attribMutex.lock(); + float screenX = (x - myXMin - myCartWidth/2) * myWidth / myCartWidth; + float screenY = (y - myYMin - myCartHeight/2) * myHeight / myCartHeight; + attribMutex.unlock(); + return Background::getPixel(screenX, screenY); +} + +/*! \brief Activates the corresponding Shader for a given Drawable. + * \param sType Unsigned int with a corresponding value for each type of Shader. + */ +void CartesianBackground::selectShaders(unsigned int sType) { + Shader * program = 0; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + unsigned int aspectLoc = glGetUniformLocation(program->ID, "aspect"); + glm::mat4 aspect = glm::mat4(1.0f); + aspect = glm::scale(aspect, glm::vec3((myCartWidth/myCartHeight) / ((float) myWidth/myHeight), 1.0, 1.0)); + glUniformMatrix4fv(aspectLoc, 1, GL_FALSE, glm::value_ptr(aspect)); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)myCartWidth/(float)myCartHeight, 0.1f, 5000.0f); + glm::mat4 view = myCamera->getViewMatrix(); + glm::mat4 model = glm::mat4(1.0f); + + glUniformMatrix4fv(glGetUniformLocation(program->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "view"), 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); +} + + /*! + * \brief Zoom the CartesianBackground with a given center. + * \details This function will re-center the CartesianBackground at the given coordinates, then zoom with + * respect to the given scale. + * \param x The coordinate to re-center the screen on. + * \param y The coordinate to re-center the screen on. + * \param scale The zoom scale compared to the original. Less than 1 zooms in, greater than 1 zooms out. + * \note This function will automatically maintain the current aspect ratio. + */ +void CartesianBackground::zoom(Decimal x, Decimal y, Decimal scale) { + attribMutex.lock(); + Decimal newWidth = myCartWidth * scale; + Decimal newHeight = myCartHeight * scale; + myXMin = x - .5 * newWidth; + myXMax = x + .5 * newWidth; + myYMin = y - .5 * newHeight; + myYMax = y + .5 * newHeight; + myCartWidth = newWidth; + myCartHeight = newHeight; + pixelWidth = myCartWidth / (myWidth - 1); + pixelHeight = myCartHeight / (myHeight - 1); //Minor hacky fix + vertices[0] = vertices[11] = vertices[21] = vertices[10] = vertices[26] = vertices[20] = -0.5 * ((myCartHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myCartHeight / 2) / tan(glm::pi()/6)); // x + y + vertices[5] = vertices[1] = vertices[15] = vertices[6] = vertices[25] = vertices[16] = 0.5 * ((myCartHeight / 2) / tan(glm::pi()/6) + myWorldZ) / ((myCartHeight / 2) / tan(glm::pi()/6)); // x + y + attribMutex.unlock(); +} + + /*! + * \brief Zoom the CartesianBackground with the given bounding (Cartesian) coordinates. + * \details This function will zoom the CartesianBackground with respect to the given bounding coordinates. + * \param x1 The left Cartesian bound. + * \param y1 The bottom Cartesian bound. + * \param x2 The right Cartesian bound. + * \param y2 The top Cartesian bound. + * \note Setting the right bound lower than the left bound or the top lower than the bottom will just + * swap the variables. + * \warning This function will *NOT* automatically maintain the previous aspect ratio. + * \warning Change the aspect ratio on-the-fly only with caution. + */ +void CartesianBackground::zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2) { + attribMutex.lock(); + Decimal scale = (std::abs(x2 - x1) / myCartWidth + std::abs(y2 - y1) / myCartHeight) / 2.0; + attribMutex.unlock(); + zoom((x2 + x1) / 2, (y2 + y1) / 2, scale); +} + +} \ No newline at end of file diff --git a/src/TSGL/CartesianBackground.h b/src/TSGL/CartesianBackground.h new file mode 100644 index 000000000..46a307a40 --- /dev/null +++ b/src/TSGL/CartesianBackground.h @@ -0,0 +1,87 @@ +/* + * CartesianBackground.h extends Drawable and provides a class for drawing TSGL primitives procedurally onto a cartesian background. + */ + +#ifndef CARTESIAN_BACKGROUND_H_ +#define CARTESIAN_BACKGROUND_H_ + +#include "Background.h" +#include "Function.h" // For drawing math functions on the screen +#include "Util.h" + +namespace tsgl { + +typedef Decimal (*functionPointer)(Decimal x); + +/*! \class CartesianBackground + * \brief Draw a procedurally drawn CartesianBackground for the Canvas. + * \details CartesianBackground is a class for holding a framebuffer of color data. + */ +class CartesianBackground : public Background { +protected: + Decimal myCartWidth, myCartHeight; + Decimal myXMin, myXMax, myYMin, myYMax; + Decimal pixelWidth, pixelHeight; // cartWidth/window.w(), cartHeight/window.h() + + virtual void selectShaders(unsigned int sType) override; +public: + CartesianBackground(GLint width, GLint height, Decimal xMin, Decimal yMin, Decimal xMax, Decimal yMax, const ColorFloat &c = WHITE); + + virtual void draw(); + + virtual void drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY); + + void drawFunction(const Function &function, ColorFloat color = BLACK); + + void drawFunction(functionPointer &function, ColorFloat color = BLACK); + + void drawPartialFunction(functionPointer &function, Decimal min, Decimal max, ColorFloat color = BLACK); + + virtual void drawPixel(float x, float y, ColorInt c); + + /*! + * \brief Accessor for the CartesianBackground's Cartesian height. + * \return The Cartesian height of the CartesianBackground. + */ + Decimal getCartHeight() { return myCartHeight; } + + /*! + * \brief Accessor for the CartesianBackground's Cartesian width. + * \return The Cartesian width of the CartesianBackground. + */ + Decimal getCartWidth() { return myCartWidth; } + + /*! + * \brief Accessor for the CartesianBackground's right bound. + * \return The real number corresponding the right of the CartesianBackground. + */ + Decimal getMaxX() { return myXMax; } + + /*! + * \brief Accessor for the CartesianBackground's top bound. + * \return The real number corresponding the top of the CartesianBackground. + */ + Decimal getMaxY() { return myYMax; } + + /*! + * \brief Accessor for the CartesianBackground's left bound. + * \return The real number corresponding the left of the CartesianBackground. + */ + Decimal getMinX() { return myXMin; } + + /*! + * \brief Accessor for the CartesianBackground's bottom bound. + * \return The real number corresponding the bottom of the CartesianBackground. + */ + Decimal getMinY() { return myYMin; } + + virtual ColorInt getPixel(float x, float y); + + void zoom(Decimal x, Decimal y, Decimal scale); + + void zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2); +}; + +} + +#endif /* CARTESIAN_BACKGROUND_H_ */ \ No newline at end of file diff --git a/src/TSGL/CartesianCanvas.cpp b/src/TSGL/CartesianCanvas.cpp index 5781fd781..34cb2e801 100644 --- a/src/TSGL/CartesianCanvas.cpp +++ b/src/TSGL/CartesianCanvas.cpp @@ -13,7 +13,7 @@ namespace tsgl { * have a 4:3 aspect ratio. */ CartesianCanvas::CartesianCanvas(double timerLength) - : Canvas(timerLength) { + : Canvas(timerLength, new CartesianBackground(1.2*Canvas::getDisplayHeight(), 0.7*1.2*Canvas::getDisplayHeight(), -400, -300, 400, 300)) { recomputeDimensions(-400, -300, 400, 300); } @@ -35,1049 +35,11 @@ CartesianCanvas::CartesianCanvas(double timerLength) * and timer length. */ CartesianCanvas::CartesianCanvas(int x, int y, int width, int height, Decimal xMin, Decimal yMin, Decimal xMax, - Decimal yMax, std::string t, double timerLength) - : Canvas(x, y, width, height, t, timerLength) { + Decimal yMax, std::string t, ColorFloat backgroundColor, double timerLength) + : Canvas(x, y, width, height, t, backgroundColor, new CartesianBackground(width, height, xMin, yMin, xMax, yMax, backgroundColor), timerLength) { recomputeDimensions(xMin, yMin, xMax, yMax); } - /*! - * \brief Draws axes on the Cartesian Canvas. - * \details This function draws axes (with tick marks) on the CartesianCanvas, centered at the - * given (Cartesian) coordinates - * \param originX The horizontal location of the y-axis line. - * \param originY The vertical location of the x-axis line. - * \param spacingX The distance between marks on the x-axis. - * \param spacingY The distance between marks on the y-axis. - */ -void CartesianCanvas::drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY) { - drawLine(maxX, originY, minX, originY); // Make the two axes - drawLine(originX, maxY, originX, minY); - - if (spacingX != 0.0) { - if (spacingX < 0.0) spacingX = -spacingX; - - for (Decimal x_ = originX + spacingX; x_ < maxX; x_ += spacingX) { - drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); - } - for (Decimal x_ = originX - spacingX; x_ > minX; x_ -= spacingX) { - drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); - } - } - if (spacingY != 0.0) { - if (spacingY < 0.0) spacingY = -spacingY; - - for (Decimal y_ = originY + spacingY; y_ < maxY; y_ += spacingY) { - drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); - } - for (Decimal y_ = originY - spacingY; y_ > minY; y_ -= spacingY) { - drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); - } - } -} - - /*! - * \brief Draws a circle with monocolored fill or outline. - * \details This function draws a circle with the given center, radius, color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color The color of the circle - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, color, filled); -} - - /*! - * \brief Draws a circle with multicolored fill or outline. - * \details This function draws a circle with the given center, radius, color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color An array of colors for the circle - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, color, filled); -} - - /*! - * \brief Draws a circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A color for the circle's fill. - * \param outlineColor A color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the circle's fill. - * \param outlineColor A color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A color for the circle's fill. - * \param outlineColor An array of colors for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of color for the circle's fill. - * \param outlineColor An array of color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a Concave polygon with monocolored fill or outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param color A color for the said vertices. - * \param filled Whether the Concave polygon should be filled in or not - * (set to true by default). - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with multicolored fill or outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the Concave polygon should be filled in or not - * (set to true by default). - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with different monocolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor A color for the concave polygon's fill. - * \param outlineColor A color for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with multicolored fill and monocolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor An array of colors for the concave polygon's fill. - * \param outlineColor A color for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with monocolored fill and multicolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor A color for the concave polygon's fill. - * \param outlineColor An array of colors for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with different multicolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor An array of colors for the concave polygon's fill. - * \param outlineColor An array of colors for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with monocolored fill or outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param color A color for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with multicolored fill or outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with different monocolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor A color for the polygon's fill. - * \param outlineColor A color for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with multicolored fill and monocoloredoutline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor An array of colors for the polygon's fill. - * \param outlineColor A color for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with monocolored fill and multicolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor A color for the polygon's fill. - * \param outlineColor An array of colors for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with different multicolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor An array of colors for the polygon's fill. - * \param outlineColor An array of colors for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Plots a function on the screen. - * \details This function receives a TSGL Function instance as a parameter and plots the function on the CartesianCanvas. - * \param function Reference to the Function to plot. - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - */ -void CartesianCanvas::drawFunction(const Function &function, float sleepTime, ColorFloat color) { - if (sleepTime > 0.0f) { - bool first = true; - Decimal lastX, lastY, y; - for (Decimal x = minX; x < maxX; x += pixelWidth) { - if (!isOpen()) break; - y = function.valueAt(x); - if (!first) - drawLine(lastX,lastY,x,y,color); - first = false; - lastX = x; - lastY = y; - if (y > minY && y < maxY) //Don't waste time if it's offscreen - sleepFor(sleepTime); - } - } else { - int screenX = 0, screenY = 0; - int size = (maxX - minX) / pixelWidth; - Polyline *p = new Polyline(size); - Decimal x = minX; - for (int i = 0; i < size; ++i) { - getScreenCoordinates(x, function.valueAt(x), screenX, screenY); - p->addVertex(screenX, screenY, color); - x += pixelWidth; - } - drawDrawable(p); - } -} - - /*! - * \brief Plots a function on the screen. - * \details This function receives a pointer to a function method as a parameter and plots the function on - * the CartesianCanvas. - * \param function Pointer to the function-drawing method to plot. - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. - */ -void CartesianCanvas::drawFunction(functionPointer &function, float sleepTime, ColorFloat color) { - drawPartialFunction(function,minX,maxX,sleepTime,color); -} - - /*! - * \brief Draws an image. - * \details This function draws an Image with the given coordinates and dimensions. - * \param function The name of the file to load the image from. - * \param x The x coordinate of the Image's left edge. - * \param y The y coordinate of the Image's top edge. - * \param w The width of the Image. - * \param h The height of the Image. - * \param a The alpha with which to draw the Image - * (set to 1.0f by default). - * \note Identical to Canvas::drawImage(). - */ -void CartesianCanvas::drawImage(std::string function, Decimal x, Decimal y, Decimal w, Decimal h, float a) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x, y, actualX1, actualY1); - getScreenCoordinates(x + w, y - h, actualX2, actualY2); - - Canvas::drawImage(function, actualX1, actualY1, actualX2 - actualX1, actualY2 - actualY1, a); -} - - /*! - * \brief Draws a monocolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color The color of the line - * (set to BLACK by default). - * \note Identical to Canvas::drawLine(). - */ -void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - - Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); -} - - /*! - * \brief Draws a multicolored line. - * \details This function draws a Line at the given coordinates with the given coloring. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color An array of colors of the line endpoints - * (set to BLACK by default). - * \note Identical to Canvas::drawLine(). - */ -void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - - Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); -} - - /*! - * \brief Plots part of a function on the screen. - * \details This function receives a pointer to a function method as a parameter and plots the function on - * the CartesianCanvas between the specified minimum and maximum coordinates. - * \param function Pointer to the function-drawing method to plot. - * \param min Minimum x value to evaluate and plot - * \param max Maximum x value to evaluate and plot - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. - */ -void CartesianCanvas::drawPartialFunction(functionPointer &function, Decimal min, Decimal max, float sleepTime, ColorFloat color) { - if (sleepTime > 0.0f) { - bool first = true; - Decimal lastX, lastY, y; - for (Decimal x = min; x < max; x += pixelWidth) { - if (!isOpen()) break; - y = (function)(x); - if (!first) - drawLine(lastX,lastY,x,y,color); - first = false; - lastX = x; - lastY = y; - if (y > minY && y < maxY) //Don't waste time if it's offscreen - sleepFor(sleepTime); - } - } else { - int screenX = 0, screenY = 0; - int size = 1 + ceil((max - min) / pixelWidth); - Polyline *p = new Polyline(size); - Decimal x = min; - for (int i = 0; i < size; ++i) { - getScreenCoordinates(x, (function)(x), screenX, screenY); - p->addVertex(screenX, screenY, color); - x += pixelWidth; - } - drawDrawable(p); - } -} - - /*! - * \brief Draws a single pixel, specified in row,column format. - * \details This function draws a pixel at the given screen coordinates with the given color. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. - * \param row The row (y-position) of the pixel. - * \param col The column (x-position) of the pixel. - * \param color The color of the point (set to BLACK by default). - * \see drawPixel() - * \note Identical to Canvas::drawPixel(). - */ -void CartesianCanvas::drawPixel(Decimal row, Decimal col, ColorFloat color) { - drawPoint(col, row, color); -} - - /*! - * \brief Draws a single pixel, specified in x,y format. - * \details This function draws a pixel at the given Cartesian coordinates with the given color. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. - * \param x The x position of the point. - * \param y The y position of the point. - * \param color The color of the point (set to BLACK by default). - * \see drawPoint() - * \note Identical to Canvas::drawPoint(). - */ -void CartesianCanvas::drawPoint(Decimal x, Decimal y, ColorFloat color) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - if (atiCard) - Canvas::drawPoint(actualX, actualY-1, color); - else - Canvas::drawPoint(actualX, actualY, color); -} - - /*! - * \brief Draws a rectangle with monocolored fill or outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color The color of the rectangle - * (set to BLACK by default). - * \param filled Whether the rectangle should be filled - * (set to true by default). - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color, bool filled) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); -} - - /*! - * \brief Draws a rectangle with multicolored fill or outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color An array of colors for the rectangle - * (set to BLACK by default). - * \param filled Whether the rectangle should be filled - * (set to true by default). - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); -} - - /*! - * \brief Draws a rectangle with different monocolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A color for the Rectangle's fill - * \param outlineColor A color for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with multicolored fill and monocolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor A color for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with monocolored fill and multicolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A color for the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with different multicolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \paramtexts The string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \note Identical to Canvas::drawText(std::string,..). - */ -void CartesianCanvas::drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - Canvas::drawText(text, actualX, actualY, size, color, fontFileName); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \param text The UTF8-encoded string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \note Identical to Canvas::drawText(std::wstring,..). - */ -void CartesianCanvas::drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - Canvas::drawText(text, actualX, actualY, size, color, fontFileName); -} - - /*! - * \brief Draw a triangle with monocolored fill or outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color A color for the Triangle (set to BLACK by default). - * \param filled Whether the Triangle should be filled (set to true by default). - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color, bool filled) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); -} - - /*! - * \brief Draw a triangle with multicolored fill or outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color An array of colors for the Triangle. - * \param filled Whether the Triangle should be filled (set to true by default). - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); -} - - /*! - * \brief Draw a triangle with different monocolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A color for the Triangle's fill. - * \param outlineColor A color for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with multicolored fill and monocolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor A color for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with monocolored fill and multicolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A color for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with different multicolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draws an arbitrary triangle strip with monocolored fill or outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param color A color for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false) - * (set to true by default). - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with multicolored fill or outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param color An array of colors for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false) - * (set to true by default). - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with different monocolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor A color for the triangle strip's fill. - * \param outlineColor A color for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with multicolored fill and monocolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor An array of colors for the triangle strip's fill. - * \param outlineColor A color for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with monocolored fill and multicolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor A color for the triangle strip's fill. - * \param outlineColor An array of colors for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with different multicolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor An array of colors for the triangle strip's fill. - * \param outlineColor An array of colors for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - /*! * \brief Translates Cartesian coordinates into window coordinates. * \details getCartesianCoordinates() takes a pair of on-screen coordinates and translates them to Cartesian @@ -1092,70 +54,6 @@ void CartesianCanvas::getCartesianCoordinates(int screenX, int screenY, Decimal cartY = minY - (screenY - getWindowHeight()) * cartHeight / getWindowHeight(); } - /*! - * \brief Accessor for the CartesianCanvas's Cartesian height. - * \return The Cartesian height of the CartesianCanvas. - */ -Decimal CartesianCanvas::getCartHeight() { - return cartHeight; -} - - /*! - * \brief Accessor for the CartesianCanvas's Cartesian width. - * \return The Cartesian width of the CartesianCanvas. - */ -Decimal CartesianCanvas::getCartWidth() { - return cartWidth; -} - - /*! - * \brief Accessor for the CartesianCanvas's effective pixel height. - * \return The height corresponding to a single pixel in the current CartesianCanvas. - */ -Decimal CartesianCanvas::getPixelHeight() { - return pixelHeight; -} - - /*! - * \brief Accessor for the CartesianCanvas's effective pixel width. - * \return The width corresponding to a single pixel in the current CartesianCanvas. - */ -Decimal CartesianCanvas::getPixelWidth() { - return pixelWidth; -} - - /*! - * \brief Accessor for the CartesianCanvas's right bound. - * \return The real number corresponding the right of the CartesianCanvas. - */ -Decimal CartesianCanvas::getMaxX() { - return maxX; -} - - /*! - * \brief Accessor for the CartesianCanvas's top bound. - * \return The real number corresponding the top of the CartesianCanvas. - */ -Decimal CartesianCanvas::getMaxY() { - return maxY; -} - - /*! - * \brief Accessor for the CartesianCanvas's left bound. - * \return The real number corresponding the left of the CartesianCanvas. - */ -Decimal CartesianCanvas::getMinX() { - return minX; -} - - /*! - * \brief Accessor for the CartesianCanvas's bottom bound. - * \return The real number corresponding the bottom of the CartesianCanvas. - */ -Decimal CartesianCanvas::getMinY() { - return minY; -} - /*! * \brief Translates window coordinates into Cartesian coordinates. * \details getScreenCoordinates() takes a pair of Cartesian coordinates and translates them to on-screen @@ -1173,6 +71,24 @@ void CartesianCanvas::getScreenCoordinates(Decimal cartX, Decimal cartY, int &sc screenY = getWindowHeight() - 1 - round((cartY - minY) / pixelHeight + pixelHeight*0.5f); } + /*! + * \brief Accessor for the mouse's x-position in Cartesian coordinates. + * \return The Cartesian x coordinates of the mouse on the CartesianCanvas. + */ +float CartesianCanvas::getMouseX() { + float mx = (mouseX * cartWidth) / winWidth + minX; + return mx; +} + + /*! + * \brief Accessor for the mouse's y-position in Cartesian coordinates. + * \return The Cartesian y coordinates of the mouse on the CartesianCanvas. + */ +float CartesianCanvas::getMouseY() { + float my = -((mouseY * cartHeight) / winHeight + minY); + return my; +} + /*! * \brief Recomputes the CartesianCanvas's bounds. * \details This function recomputes the size variables of CartesianCanvas according to new bounds. @@ -1190,6 +106,59 @@ void CartesianCanvas::recomputeDimensions(Decimal xMin, Decimal yMin, Decimal xM cartHeight = maxY - minY; pixelWidth = cartWidth / (getWindowWidth() - 1); pixelHeight = cartHeight / (getWindowHeight() - 1); //Minor hacky fix + camera->setPosition((float) (maxX + minX) / 2, (float) (maxY + minY) / 2, ((float)cartHeight / 2) / tan(glm::pi()/6)); +} + +/*! \brief Activates the corresponding Shader for a given Drawable. + * \param sType Unsigned int with a corresponding value for each type of Shader. + */ +void CartesianCanvas::selectShaders(unsigned int sType) { + Shader * program = 0; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + unsigned int aspectLoc = glGetUniformLocation(program->ID, "aspect"); + glm::mat4 aspect = glm::mat4(1.0f); + aspect = glm::scale(aspect, glm::vec3( (cartWidth/cartHeight) / ((float) winWidth/winHeight), 1.0f, 1.0f)); + glUniformMatrix4fv(aspectLoc, 1, GL_FALSE, glm::value_ptr(aspect)); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + program->use(); + } + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)cartWidth/(float)cartHeight, 0.1f, 5000.0f); + glm::mat4 view = camera->getViewMatrix(); + glm::mat4 model = glm::mat4(1.0f); + + glUniformMatrix4fv(glGetUniformLocation(program->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "view"), 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); } /*! @@ -1278,16 +247,6 @@ void CartesianCanvas::run(void (*myFunction)(CartesianCanvas&, std::string, int) start(); myFunction(*this, s, i); wait(); } - /*! - * \brief Sleeps the internal drawing timer of a CartesianCanvas object. - * \details A timer is put to sleep until a subsequent event is ready to occur. - * \details The drawing timer is put to sleep until the next drawing frame is ready to occur. - * \note Identical to Canvas::sleep(). - */ -void CartesianCanvas::sleep() { - Canvas::sleep(); -} - /*! * \brief Zoom the CartesianCanvas with a given center. * \details This function will re-center the CartesianCanvas at the given coordinates, then zoom with @@ -1301,6 +260,8 @@ void CartesianCanvas::zoom(Decimal x, Decimal y, Decimal scale) { Decimal newWidth = cartWidth * scale; Decimal newHeight = cartHeight * scale; recomputeDimensions(x - .5 * newWidth, y - .5 * newHeight, x + .5 * newWidth, y + .5 * newHeight); + CartesianBackground* c = (CartesianBackground*) myBackground; + c->zoom(x, y, scale); } /*! @@ -1324,229 +285,229 @@ void CartesianCanvas::zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2) { /*! * \brief Runs the Unit tests for CartesianCanvas. */ -void CartesianCanvas::runTests() { - TsglDebug("Testing CartesianCanvas class..."); - CartesianCanvas c1(0.0f); - c1.setBackgroundColor(WHITE); - c1.start(); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - tsglAssert(testZoom(c1), "Unit test for zoom() functions failed!"); - tsglAssert(testRecomputeDimensions(c1), "Unit test for recomputing dimensions failed!"); - c1.stop(); - - CartesianCanvas c2(-1, -1, 800, 600, -1, -1, 3, 2,""); - c2.setBackgroundColor(WHITE); - c2.start(); - tsglAssert(testDraw(c2), "Unit test for drawing functions failed!"); - c2.wait(); - - TsglDebug("Unit tests for CartesianCanvas complete."); -} - -bool CartesianCanvas::testDraw(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - - float pw = can.getPixelWidth(); - float ph = can.getPixelHeight(); - - //Test 1: Physical to Cartesian point mapping - can.drawPoint(-1.0f,-1.0f,BLACK); //outer bottomleft - can.drawPoint(3.0f,-1.0f,BLACK); //outer bottomright - can.drawPoint(-1.0f,2.0f,BLACK); //outer topleft - can.drawPoint(3.0f,2.0f,BLACK); //outer topright - can.drawPoint(0.0f,0.0f,BLACK); //1/4 over, 1/3 down (origin) - - can.drawPoint(-1.0f+pw,-1.0f+ph,BLACK); //inner bottomleft - can.drawPoint(3.0f-pw,-1.0f+ph,BLACK); //inner bottomright - can.drawPoint(-1.0f+pw,2.0f-ph,BLACK); //inner topleft - can.drawPoint(3.0f-pw,2.0f-ph,BLACK); //inner topright - can.sleepFor(1.0f); - - if(can.getPoint(200,399).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, origin pixel for testDraw() failed!"); - } - if(can.getPoint(0,0).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer topleft pixel for testDraw() failed!"); - } - if(can.getPoint(799,0).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer topright pixel for testDraw() failed!"); - } - if(can.getPoint(0,599).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer bottomleft pixel for testDraw() failed!"); - } - if(can.getPoint(799,599).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer bottomright pixel for testDraw() failed!"); - } - - if(can.getPoint(1,1).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner topleft pixel for testDraw() failed!"); - } - if(can.getPoint(798,1).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner topright pixel for testDraw() failed!"); - } - if(can.getPoint(1,598).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner bottomleft pixel for testDraw() failed!"); - } - if(can.getPoint(798,598).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner bottomright pixel for testDraw() failed!"); - } - - //Results: - if(failed == 0) { - TsglDebug("Unit test for drawing passed!"); - return true; - } else { - TsglErr("This many passed for testDraw(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testDraw(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool CartesianCanvas::testZoom(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - //Test 1: Zooming out - //Had to use round() because there was a floating-point error that - //propagated to the rest of the tests after the first two - can.zoom(0, 0, 1.5); - if(round(can.getCartWidth()) == 1200 && round(can.getCartHeight()) == 900) { - passed++; - } else { - failed++; - TsglErr("Test 1, Zooming out for testZoom() failed!"); - } - - //Test 2: Zooming in - can.zoom(0, 0, .5); - if(round(can.getCartWidth()) == 600 && round(can.getCartHeight()) == 450) { - passed++; - } else { - failed++; - TsglErr("Test 2, Zooming in for testZoom() failed!"); - } - - //Test 3: Zooming out/in on a different point - - //Zooming out.... - can.zoom(10, 10, 1.2); - if(round(can.getCartWidth()) == 720 && round(can.getCartHeight()) == 540) { - passed++; - } else { - failed++; - TsglErr("Test 3, Zooming out on a different point for testZoom() failed!"); - } - - //Zooming in.... - can.zoom(15, 20, .9); - if(round(can.getCartWidth()) == 648 && round(can.getCartHeight()) == 486) { - passed++; - } else { - failed++; - TsglErr("Test 3, Zooming in on a different point for testZoom() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - TsglDebug("Unit test for zooming in & out passed!"); - return true; - } else { - TsglErr("This many passed for testZoom(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testZoom(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool CartesianCanvas::testRecomputeDimensions(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - Decimal xMin, xMax; - Decimal yMin, yMax; - //Test 1: Positive values only (with 0.0) - xMin = 0.0; - xMax = 500.0; - yMin = 0.0; - yMax = 500.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - if(can.getCartWidth() == 500.0 && can.getCartHeight() == 500.0) { - passed++; - } else { - failed++; - TsglErr("Test 1, Positive values only for testRecomputeDimensions() failed!"); - } - - //Test 2: Negative values included - xMin = xMax = yMin = yMax = 0.0; - xMin = -300.0; - xMax = 900.0; - yMin = -500.0; - yMax = 1000.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - - if(can.getCartWidth() == 1200.0 && can.getCartHeight() == 1500.0) { - passed++; - } else { - failed++; - TsglErr("Test 2, Negative values for testRecomputeDimensions() failed!"); - } - - //Test 3: Same as Test 2, but negative values are max - xMin = xMax = yMin = yMax = 0.0; - xMin = -900.0; - xMax = -100.0; - yMin = -800.0; - yMax = -50.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - - if(can.getCartWidth() == 800.0 && can.getCartHeight() == 750.0) { - passed++; - } else { - failed++; - TsglErr("Test 3, Max negative values for testRecomputeDimensions() failed!"); - } - - if(passed == 3 && failed == 0) { - TsglDebug("Unit test for recomputing dimensions passed!"); - return true; - } else { - TsglErr("This many tests passed for testRecomputeDimensions(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests failed for testRecomputeDimensions(): "); - std::cout << " " << failed << std::endl; - return false; - } -} +// void CartesianCanvas::runTests() { +// TsglDebug("Testing CartesianCanvas class..."); +// CartesianCanvas c1(0.0f); +// c1.setBackgroundColor(WHITE); +// c1.start(); + +// std::this_thread::sleep_for(std::chrono::seconds(1)); +// tsglAssert(testZoom(c1), "Unit test for zoom() functions failed!"); +// tsglAssert(testRecomputeDimensions(c1), "Unit test for recomputing dimensions failed!"); +// c1.stop(); + +// CartesianCanvas c2(-1, -1, 800, 600, -1, -1, 3, 2,""); +// c2.setBackgroundColor(WHITE); +// c2.start(); +// tsglAssert(testDraw(c2), "Unit test for drawing functions failed!"); +// c2.wait(); + +// TsglDebug("Unit tests for CartesianCanvas complete."); +// } + +// bool CartesianCanvas::testDraw(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; + +// float pw = can.getPixelWidth(); +// float ph = can.getPixelHeight(); + +// //Test 1: Physical to Cartesian point mapping +// can.drawPoint(-1.0f,-1.0f,BLACK); //outer bottomleft +// can.drawPoint(3.0f,-1.0f,BLACK); //outer bottomright +// can.drawPoint(-1.0f,2.0f,BLACK); //outer topleft +// can.drawPoint(3.0f,2.0f,BLACK); //outer topright +// can.drawPoint(0.0f,0.0f,BLACK); //1/4 over, 1/3 down (origin) + +// can.drawPoint(-1.0f+pw,-1.0f+ph,BLACK); //inner bottomleft +// can.drawPoint(3.0f-pw,-1.0f+ph,BLACK); //inner bottomright +// can.drawPoint(-1.0f+pw,2.0f-ph,BLACK); //inner topleft +// can.drawPoint(3.0f-pw,2.0f-ph,BLACK); //inner topright +// can.sleepFor(1.0f); + +// if(can.getPoint(200,399).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, origin pixel for testDraw() failed!"); +// } +// if(can.getPoint(0,0).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer topleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(799,0).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer topright pixel for testDraw() failed!"); +// } +// if(can.getPoint(0,599).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer bottomleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(799,599).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer bottomright pixel for testDraw() failed!"); +// } + +// if(can.getPoint(1,1).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner topleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(798,1).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner topright pixel for testDraw() failed!"); +// } +// if(can.getPoint(1,598).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner bottomleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(798,598).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner bottomright pixel for testDraw() failed!"); +// } + +// //Results: +// if(failed == 0) { +// TsglDebug("Unit test for drawing passed!"); +// return true; +// } else { +// TsglErr("This many passed for testDraw(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many failed for testDraw(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } + +// bool CartesianCanvas::testZoom(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; +// //Test 1: Zooming out +// //Had to use round() because there was a floating-point error that +// //propagated to the rest of the tests after the first two +// can.zoom(0, 0, 1.5); +// if(round(can.getCartWidth()) == 1200 && round(can.getCartHeight()) == 900) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Zooming out for testZoom() failed!"); +// } + +// //Test 2: Zooming in +// can.zoom(0, 0, .5); +// if(round(can.getCartWidth()) == 600 && round(can.getCartHeight()) == 450) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, Zooming in for testZoom() failed!"); +// } + +// //Test 3: Zooming out/in on a different point + +// //Zooming out.... +// can.zoom(10, 10, 1.2); +// if(round(can.getCartWidth()) == 720 && round(can.getCartHeight()) == 540) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Zooming out on a different point for testZoom() failed!"); +// } + +// //Zooming in.... +// can.zoom(15, 20, .9); +// if(round(can.getCartWidth()) == 648 && round(can.getCartHeight()) == 486) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Zooming in on a different point for testZoom() failed!"); +// } + +// //Results: +// if(passed == 4 && failed == 0) { +// TsglDebug("Unit test for zooming in & out passed!"); +// return true; +// } else { +// TsglErr("This many passed for testZoom(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many failed for testZoom(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } + +// bool CartesianCanvas::testRecomputeDimensions(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; +// Decimal xMin, xMax; +// Decimal yMin, yMax; +// //Test 1: Positive values only (with 0.0) +// xMin = 0.0; +// xMax = 500.0; +// yMin = 0.0; +// yMax = 500.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); +// if(can.getCartWidth() == 500.0 && can.getCartHeight() == 500.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Positive values only for testRecomputeDimensions() failed!"); +// } + +// //Test 2: Negative values included +// xMin = xMax = yMin = yMax = 0.0; +// xMin = -300.0; +// xMax = 900.0; +// yMin = -500.0; +// yMax = 1000.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); + +// if(can.getCartWidth() == 1200.0 && can.getCartHeight() == 1500.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, Negative values for testRecomputeDimensions() failed!"); +// } + +// //Test 3: Same as Test 2, but negative values are max +// xMin = xMax = yMin = yMax = 0.0; +// xMin = -900.0; +// xMax = -100.0; +// yMin = -800.0; +// yMax = -50.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); + +// if(can.getCartWidth() == 800.0 && can.getCartHeight() == 750.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Max negative values for testRecomputeDimensions() failed!"); +// } + +// if(passed == 3 && failed == 0) { +// TsglDebug("Unit test for recomputing dimensions passed!"); +// return true; +// } else { +// TsglErr("This many tests passed for testRecomputeDimensions(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many tests failed for testRecomputeDimensions(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } //-----------------End Unit testing---------------------------------------------------- } diff --git a/src/TSGL/CartesianCanvas.h b/src/TSGL/CartesianCanvas.h index 258c81bfd..ce61aba84 100644 --- a/src/TSGL/CartesianCanvas.h +++ b/src/TSGL/CartesianCanvas.h @@ -6,13 +6,9 @@ #define CARTESIANCANVAS_H_ #include "Canvas.h" // We extend Canvas -#include "Function.h" // For drawing math functions on the screen -#include "Util.h" namespace tsgl { -typedef Decimal (*functionPointer)(Decimal x); - /*! * \class CartesianCanvas * \brief Canvas extended with Cartesian drawing operations. @@ -27,132 +23,77 @@ class CartesianCanvas : public Canvas { Decimal minX, maxX, minY, maxY; // Bounding Cartesian coordinates for the window Decimal pixelWidth, pixelHeight; // cartWidth/window.w(), cartHeight/window.h() - static bool testZoom(CartesianCanvas& can); // Unit test for zoom() methods - static bool testRecomputeDimensions(CartesianCanvas& can); // Unit test for recomputeDimensions() - static bool testDraw(CartesianCanvas& can); // Unit test for drawing + // static bool testZoom(CartesianCanvas& can); // Unit test for zoom() methods + // static bool testRecomputeDimensions(CartesianCanvas& can); // Unit test for recomputeDimensions() + // static bool testDraw(CartesianCanvas& can); // Unit test for drawing public: CartesianCanvas(double timerLength = 0.0); CartesianCanvas(int x, int y, int width, int height, Decimal xMin, Decimal yMin, Decimal xMax, Decimal yMax, - std::string t, double timerLength = 0.0); - - void drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled = true); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled = true); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); - - void drawFunction(const Function &function, float sleepTime = 0.0f, ColorFloat color = BLACK); - - void drawFunction(functionPointer &function, float sleepTime = 0.0f, ColorFloat color = BLACK); - - void drawImage(std::string filename, Decimal x, Decimal y, Decimal w, Decimal h, float a = 1.0f); - - void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color = BLACK); - - void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]); - - void drawPartialFunction(functionPointer &function, Decimal min, Decimal max, - float sleepTime = 0.0f, ColorFloat color = BLACK); - - void drawPixel(Decimal row, Decimal col, ColorFloat color = BLACK); - - void drawPoint(Decimal x, Decimal y, ColorFloat color = BLACK); - - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color = BLACK, bool filled = true); + std::string t, ColorFloat backgroundColor = GRAY, double timerLength = 0.0); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled = true); - - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor); - - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor); - - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]); - - void drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); - - void drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color = BLACK, bool filled = true); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled = true); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); + virtual CartesianBackground * getBackground() override { return (CartesianBackground *) myBackground; } void getCartesianCoordinates(int screenX, int screenY, Decimal &cartX, Decimal &cartY); - Decimal getCartHeight(); - - Decimal getCartWidth(); - - Decimal getPixelHeight(); - - Decimal getPixelWidth(); - - Decimal getMaxX(); - - Decimal getMaxY(); - - Decimal getMinX(); - - Decimal getMinY(); + /*! + * \brief Accessor for the CartesianCanvas's Cartesian height. + * \return The Cartesian height of the CartesianCanvas. + */ + Decimal getCartHeight() { return cartHeight; } + + /*! + * \brief Accessor for the CartesianCanvas's Cartesian width. + * \return The Cartesian width of the CartesianCanvas. + */ + Decimal getCartWidth() { return cartWidth; } + + virtual float getMouseX(); + + virtual float getMouseY(); + + /*! + * \brief Accessor for the CartesianCanvas's effective pixel height. + * \return The height corresponding to a single pixel in the current CartesianCanvas. + */ + Decimal getPixelHeight() { return pixelHeight; } + + /*! + * \brief Accessor for the CartesianCanvas's effective pixel width. + * \return The width corresponding to a single pixel in the current CartesianCanvas. + */ + Decimal getPixelWidth() { return pixelWidth; } + + /*! + * \brief Accessor for the CartesianCanvas's right bound. + * \return The real number corresponding the right of the CartesianCanvas. + */ + Decimal getMaxX() { return maxX; } + + /*! + * \brief Accessor for the CartesianCanvas's top bound. + * \return The real number corresponding the top of the CartesianCanvas. + */ + Decimal getMaxY() { return maxY; } + + /*! + * \brief Accessor for the CartesianCanvas's left bound. + * \return The real number corresponding the left of the CartesianCanvas. + */ + Decimal getMinX() { return minX; } + + /*! + * \brief Accessor for the CartesianCanvas's bottom bound. + * \return The real number corresponding the bottom of the CartesianCanvas. + */ + Decimal getMinY() { return minY; } void getScreenCoordinates(Decimal cartX, Decimal cartY, int &screenX, int &screenY); void recomputeDimensions(Decimal xMin, Decimal yMin, Decimal xMax, Decimal yMax); + virtual void selectShaders(unsigned int sType) override; + void run(void (*myFunction)(CartesianCanvas&)); void run(void (*myFunction)(CartesianCanvas&, int), int i); @@ -169,13 +110,11 @@ class CartesianCanvas : public Canvas { void run(void (*myFunction)(CartesianCanvas&, std::string, int), std::string s, int i); - void sleep(); - void zoom(Decimal x, Decimal y, Decimal scale); void zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2); - static void runTests(); + // static void runTests(); }; } diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 72503aebb..043ee5428 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -3,77 +3,135 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new monocolored filled or outlined Circle. - * \details This function draws a circle with the given center, radius, color, and outline color. + * \brief Explicitly constructs a new monocolored filled Circle. + * \details This function draws a circle with the given center, radius, 3D rotation, color. * \param x The x coordinate of the circle's center. * \param y The y coordinate of the circle's center. + * \param z The z coordinate of the circle's center. * \param radius The radius of the circle in pixels. - * \param color The color of the circle's fill or outline - * \param filled Whether the circle should be filled - * (set to true by default). + * \param yaw The circle's yaw in 3D space. + * \param pitch The circle's pitch in 3D space. + * \param roll The circle's roll in 3D space. + * \param color The color of the circle's fill */ -Circle::Circle(float x, float y, float radius, const ColorFloat color, bool filled) -: Ellipse(x,y,radius,radius,color,filled) { } //Create an Ellipse with equal x and y radii +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(radius + 5) + 1,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + verticesPerColor = (myRadius + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; + attribMutex.unlock(); + addVertex(0,0,0,color); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } +} /*! - * \brief Explicitly constructs a new multicolored filled or outlined Circle. - * \details This function draws a circle with the given center, radius, color, and outline color. + * \brief Explicitly constructs a new multicolored filled Circle. + * \details This function draws a circle with the given center, radius, roation, and fill color. * \param x The x coordinate of the circle's center. * \param y The y coordinate of the circle's center. + * \param z The z coordinate of the circle's center. * \param radius The radius of the circle in pixels. - * \param color An array of colors for the Circle's fill or outline - * \param filled Whether the circle should be filled - * (set to true by default). + * \param yaw The circle's yaw in 3D space. + * \param pitch The circle's pitch in 3D space. + * \param roll The circle's roll in 3D space. + * \param color An array of colors for the Circle's fill */ -Circle::Circle(float x, float y, float radius, const ColorFloat color[], bool filled) -: Ellipse(x,y,radius,radius,color,filled) { } //Create an Ellipse with equal x and y radii +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(GLint) (radius + 5) + 1,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + verticesPerColor = (myRadius + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; + attribMutex.unlock(); + addVertex(0,0,0,color[0]); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } +} -/*! - * \brief Explicitly constructs a new Circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor The color of the circle's fill - * \param outlineColor The color of the circle's outline +/** + * \brief Mutates the radius of the Circle. + * \param radius The Circle's new radius. */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius = radius; + myXScale = myYScale = radius; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor The color of the circle's outline +/** + * \brief Mutates the radius of the Circle by the parameter amount. + * \param delta The amount by which to change the radius of the Circle. */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor The color of the circle's fill - * \param outlineColor An array of colors for the Circle's outline +/** + * \brief Sets the Circle to a new array of colors. + * \param c An array of the new ColorFloats. */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor[]) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0f; + vertices[3] = c[0].R; + vertices[4] = c[0].G; + vertices[5] = c[0].B; + vertices[6] = c[0].A; + myAlpha += c[0].A; + int colorIndex; + for (int i = 1; i < numberOfVertices; ++i) { + colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); + vertices[i*7 + 3] = c[colorIndex].R; + vertices[i*7 + 4] = c[colorIndex].G; + vertices[i*7 + 5] = c[colorIndex].B; + vertices[i*7 + 6] = c[colorIndex].A; + myAlpha += c[colorIndex].A; + } + myAlpha /= numberOfVertices; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor An array of colors for the Circle's outline +/** + * \brief Accessor for Circle's colors. + * \details Populates the reference parameter vector with a ColorFloat for each section of Circle. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Circle will be pushed. + * \note Overrides Shape::getColors(). */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor[]) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::getColors(std::vector &colorVec) { + attribMutex.lock(); + for (int i = 0; i < numberOfVertices; i+=verticesPerColor) { + colorVec.push_back(ColorFloat(vertices[i*7+3],vertices[i*7+4],vertices[i*7+5],vertices[i*7+6])); + } + attribMutex.unlock(); +} } \ No newline at end of file diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index 4b7780c6f..5b777a5fc 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -1,32 +1,42 @@ /* -* Circle.h extends Ellipse and provides a class for drawing a circle to a Canvas. +* Circle.h extends ConvexPolygon and provides a class for drawing a circle to a Canvas. */ #ifndef CIRCLE_H_ #define CIRCLE_H_ -#include "Ellipse.h" // For extending our Ellipse object +#include "ConvexPolygon.h" // For extending our ConvexPolygon object namespace tsgl { - /*! \class Circle - * \brief Draw a circle. - * \details Circle is a class for holding Shape data for a circle. - */ - class Circle : public Ellipse { - public: - Circle(float x, float y, float radius, const ColorFloat color, bool filled = true); +/*! \class Circle +* \brief Draw a circle. +* \details Circle is a class for holding Shape data for a circle. +*/ +class Circle : public ConvexPolygon { +protected: + GLfloat myRadius; + GLfloat verticesPerColor; +public: + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color); + + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]); - Circle(float x, float y, float radius, const ColorFloat color[], bool filled = true); + void setRadius(GLfloat radius); - Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor); + void changeRadiusBy(GLfloat delta); - Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor); + /*! + * \brief Accessor for the radius of the Circle. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + GLfloat getRadius() { return myRadius; } - Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor[]); + void setColor(ColorFloat c) { Shape::setColor(c); } - Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + void setColor(ColorFloat c[]); + virtual void getColors(std::vector &colorVec); }; } diff --git a/src/TSGL/Color.cpp b/src/TSGL/Color.cpp index 6eafd1f7f..8f281f492 100644 --- a/src/TSGL/Color.cpp +++ b/src/TSGL/Color.cpp @@ -102,7 +102,7 @@ ColorFloat::ColorFloat() { * \return A ColorFloat struct with equal R, G, and B values set to v, * and the specified A value. */ -ColorFloat::ColorFloat(float v, float a) { +ColorFloat::ColorFloat(GLfloat v, GLfloat a) { if (clamp(v,0,1)) TsglDebug("Out of range parameter specified for ColorFloat"); R = v; G = v; B = v; A = a; @@ -119,7 +119,7 @@ ColorFloat::ColorFloat(float v, float a) { * is out of the range 0 - 1 inclusive then an error message is given. * \return A ColorFloat struct with the specified R, G, B, and A values. */ -ColorFloat::ColorFloat(float r, float g, float b, float a) { +ColorFloat::ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { bool oor = false; oor |= clamp(r,0,1); oor |= clamp(g,0,1); diff --git a/src/TSGL/Color.h b/src/TSGL/Color.h index 8dcf62ab0..3aa7eba32 100755 --- a/src/TSGL/Color.h +++ b/src/TSGL/Color.h @@ -9,6 +9,7 @@ #include // Needed for exceptions #include // Needed for rand() #include // Needed for Windows integer / float to string conversion +#include #include "Util.h" // Clamp() #include "Error.h" // TsglErr() / TsglDebug() @@ -18,6 +19,7 @@ namespace tsgl { struct ColorFloat; //Forward declarations struct ColorInt; struct ColorHSV; +struct ColorFloat; /*! * \brief Floating point RGBA color struct. @@ -29,13 +31,13 @@ struct ColorHSV; */ struct ColorFloat { public: - float R, G, B, A; + GLfloat R, G, B, A; ColorFloat(); - ColorFloat(float v, float a = 1.0f); + ColorFloat(GLfloat v, GLfloat a = 1.0f); - ColorFloat(float r, float g, float b, float a = 1.0f); + ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0f); std::string asString(); diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index d0d6e72f5..820a4ce4e 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -4,615 +4,142 @@ namespace tsgl { /*! * \brief Explicitly constructs a new ConcavePolygon. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, bool filled, bool outlined) : Polygon(numVertices) { - setup(numVertices, filled, outlined); -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with monocolored fill or outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConcavePolygon's fill or outline. - * \param filled Whether the ConcavePolygon should be filled - * (set to true by default). - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with multicolored fill or outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConcavePolygon's fill or outline. - * \param filled Whether the ConcavePolygon should be filled - * (set to true by default). - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with different monocolored fill and outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConcavePolygon's fill. - * \param outlineColor The color of the ConcavePolygon's outline. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with multicolored fill and monocolored outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConcavePolygon's fill. - * \param outlineColor The color of the ConcavePolygon's outline. + * \details Protected explicit constructor for a ConcavePolygon object. Used as a superclass constructor. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_FAN; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); } /*! - * \brief Explicitly constructs a new ConcavePolygon with monocolored fill and multicolored outline. + * \brief Explicitly constructs a new ConcavePolygon with monocolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConcavePolygon's fill. - * \param outlineColor An array of colors for the ConcavePolygon's outline. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color A ColorFloat, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); - } +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_FAN; + numberOfVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + myXScale = myYScale = myZScale = 1; + outlineGeometryType = GL_LINE_LOOP; + numberOfOutlineVertices = numVertices; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < numVertices; i++) { + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); + } } /*! - * \brief Explicitly constructs a new ConcavePolygon with different multicolored fill and outline. + * \brief Explicitly constructs a new ConcavePolygon with multicolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConcavePolygon's fill. - * \param outlineColor An array of colors for the ConcavePolygon's outline. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); - } -} - -/*! - * \brief private helper method that works with the constructor - * \details Defines a lot of instance variables, initializes vertices and outlineVertices arrays - * \param numVertices Number of vertices on the ConcavePolygon - * \param filled Whether or not the ConcavePolygon is filled. - * \param outlined Whether or not the ConcavePolygon is outlined. - */ -void ConcavePolygon::setup(int numVertices, bool filled, bool outlined) { - numberOfOutlineVertices = numVertices+1; - size = numberOfOutlineVertices * 6; - tsize = 0; - isFilled = filled; - hasOutline = outlined; - dirty = false; - geometryType = GL_TRIANGLES; - if(filled) { - vertices = new float[size]; - } - if(outlined) { - outlineVertices = new float[size]; - } -} - - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void ConcavePolygon::addVertex(float x, float y, const ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = color.R; - outlineVertices[current + 3] = color.G; - outlineVertices[current + 4] = color.B; - outlineVertices[current + 5] = color.A; - } - current += 6; - dirty = true; - - if (current == size-6) { - if(isFilled) { - vertices[current] = vertices[0]; - vertices[current + 1] = vertices[1]; - vertices[current + 2] = vertices[2]; - vertices[current + 3] = vertices[3]; - vertices[current + 4] = vertices[4]; - vertices[current + 5] = vertices[5]; - } - if(hasOutline) { - outlineVertices[current] = outlineVertices[0]; - outlineVertices[current + 1] = outlineVertices[1]; - outlineVertices[current + 2] = outlineVertices[2]; - outlineVertices[current + 3] = outlineVertices[3]; - outlineVertices[current + 4] = outlineVertices[4]; - outlineVertices[current + 5] = outlineVertices[5]; - } - init = true; - if(isFilled) { - preprocess(); - } +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - float minX, maxX; - //Find min and max X - if(hasOutline) { - minX = maxX = outlineVertices[0]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - } else { - minX = maxX = vertices[0]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } + geometryType = GL_TRIANGLE_FAN; + numberOfVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + myXScale = myYScale = myZScale = 1; + outlineGeometryType = GL_LINE_LOOP; + numberOfOutlineVertices = numVertices; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < numVertices; i++) { + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } - myCenterX = myRotationPointX = (minX+maxX)/2; - - float minY, maxY; - //Find min and max Y - if(hasOutline) { - minY = maxY = outlineVertices[1]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else { - minY = maxY = vertices[1]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - myCenterY = myRotationPointY = (minY+maxY)/2; - attribMutex.unlock(); - } } - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param fillColor The reference variable of the fill color of the vertex. - * \param outlineColor The reference variable of the outline color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void ConcavePolygon::addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = fillColor.R; - vertices[current + 3] = fillColor.G; - vertices[current + 4] = fillColor.B; - vertices[current + 5] = fillColor.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = outlineColor.R; - outlineVertices[current + 3] = outlineColor.G; - outlineVertices[current + 4] = outlineColor.B; - outlineVertices[current + 5] = outlineColor.A; - } - current += 6; - dirty = true; - - if (current == size-6) { - if(isFilled) { - vertices[current] = vertices[0]; - vertices[current + 1] = vertices[1]; - vertices[current + 2] = vertices[2]; - vertices[current + 3] = vertices[3]; - vertices[current + 4] = vertices[4]; - vertices[current + 5] = vertices[5]; - } - if(hasOutline) { - outlineVertices[current] = outlineVertices[0]; - outlineVertices[current + 1] = outlineVertices[1]; - outlineVertices[current + 2] = outlineVertices[2]; - outlineVertices[current + 3] = outlineVertices[3]; - outlineVertices[current + 4] = outlineVertices[4]; - outlineVertices[current + 5] = outlineVertices[5]; - } - init = true; - if(isFilled) { - preprocess(); - } - attribMutex.lock(); - float minX, maxX; - - //Find min and max X - if(hasOutline) { - minX = maxX = outlineVertices[0]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - } else { - minX = maxX = vertices[0]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - } - myCenterX = myRotationPointX = (minX+maxX)/2; - - float minY, maxY; - //Find min and max Y - if(hasOutline) { - minY = maxY = outlineVertices[1]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else { - minY = maxY = vertices[1]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - myCenterY = myRotationPointY = (minY+maxY)/2; - attribMutex.unlock(); - } -} - - /*! - * \brief Determines if two lines intersect. - * \details Simulates two lines inside of a ConcavePolygon object and determines whether - * those two lines intersect. - * \param p0_x The x coordinate of the first point of the first line. - * \param p0_y The y coordinate of the first point of the first line. - * \param p1_x The x coordinate of the second point of the first line. - * \param p1_y The y coordinate of the second point of the first line. - * \param p2_x The x coordinate of the first point of the second line. - * \param p2_y The y coordinate of the first point of the second line. - * \param p3_x The x coordinate of the second point of the second line. - * \param p3_y The y coordinate of the second point of the second line. - * \returns true if the lines do intersect, false if otherwise. - */ -bool ConcavePolygon::intersects(float p0_x, float p0_y, float p1_x, float p1_y, - float p2_x, float p2_y, float p3_x, float p3_y) { - float s1_x, s1_y, s2_x, s2_y; - s1_x = p1_x - p0_x; s1_y = p1_y - p0_y; - s2_x = p3_x - p2_x; s2_y = p3_y - p2_y; - - float s, t; - s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); - t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); - - return (s >= 0 && s <= 1 && t >= 0 && t <= 1); -} - - /*! - * \brief Determines whether a point resides inside of a Triangle. - * \details Simulates a Triangle and point inside of a ConcavePolygon object and determines whether the point resides inside of - * the Triangle. - * \param px The x coordinate of the point. - * \param py The y coordinate of the point. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \returns true if the point does reside in the Triangle, false if otherwise. - */ -bool ConcavePolygon::pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3) -{ - bool b1 = ( (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2) ) <= 0.0f; - bool b2 = ( (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3) ) <= 0.0f; - bool b3 = ( (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1) ) <= 0.0f; - - return ((b1 == b2) && (b2 == b3)); -} - - /*! - * \brief Process the the ConcavePolygon vertices. - * \details This function alters the vertices array so that it will render a Concave polygon correctly - * \note This function does nothing if the vertex buffer is not yet full. - * \warning This is an order of n-cubed operation, and is thus VERY SLOW. - */ -void ConcavePolygon::preprocess() { - - if (dirty) { - dirty = false; - std::queue newvertices; - - bool clockwise = ( - ( - (vertices[6]-vertices[0]) * (vertices[13]-vertices[7]) - - (vertices[7]-vertices[1]) * (vertices[12]-vertices[6]) - ) < 0.0); - - for (int i = 0; i < size-12; i += 6) { - float x1 = vertices[i], y1 = vertices[i+1]; - for (int j = i+6; j < size-6; j += 6) { - float x2 = vertices[j], y2 = vertices[j+1]; - for (int k = j+6; k < size; k += 6) { - float x3 = vertices[k], y3 = vertices[k+1]; - - bool open = true; - for (int n = 0; n < size-6; n += 6) { - float x4 = vertices[n], y4 = vertices[n+1], x5 = vertices[n+6],y5 = vertices[n+7]; - if (pointInTriangle(x4,y4,x1,y1,x2,y2,x3,y3) || pointInTriangle(x5,y5,x1,y1,x2,y2,x3,y3)) { - open = false; break; - } - if (intersects(x1,y1,x2,y2,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x2==x5 && y2==y5) || (x1==x5 && y1==y5) || (x2==x4 && y2==y4)) ) { - open = false; break; - } - } - if (intersects(x2,y2,x3,y3,x4,y4,x5,y5)) { - if ( !( (x2==x4 && y2==y4) || (x3==x5 && y3==y5) || (x2==x5 && y2==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - if (intersects(x1,y1,x3,y3,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x3==x5 && y3==y5) || (x1==x5 && y1==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - } - - //If the angle is not open (intersects something), draw nothing - if (!open) - continue; - - //If the angle is concave, draw nothing - if ( ( ( (x2-x1) * (y3-y2) - (y2-y1) * (x3-x2) ) <= 0.0) != clockwise) { - continue; - } - - newvertices.push(x1); - newvertices.push(y1); - newvertices.push(vertices[i+2]); - newvertices.push(vertices[i+3]); - newvertices.push(vertices[i+4]); - newvertices.push(vertices[i+5]); - newvertices.push(x2); - newvertices.push(y2); - newvertices.push(vertices[j+2]); - newvertices.push(vertices[j+3]); - newvertices.push(vertices[j+4]); - newvertices.push(vertices[j+5]); - newvertices.push(x3); - newvertices.push(y3); - newvertices.push(vertices[k+2]); - newvertices.push(vertices[k+3]); - newvertices.push(vertices[k+4]); - newvertices.push(vertices[k+5]); - } - } - } - - tsize = newvertices.size(); - delete[] vertices; - vertices = new float[tsize]; - for (int i = 0; i < tsize; ++i) { - vertices[i] = newvertices.front(); - newvertices.pop(); - } - - numberOfVertices = tsize / 6; - - } - - //Debug Outline - // for (int i = 0; i < size; i += 6) { - // vertices[i+2] = 1.0f; - // vertices[i+3] = 1.0f; - // vertices[i+4] = 1.0f; - // vertices[i+5] = 1.0f; - // } - // glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), vertices, GL_DYNAMIC_DRAW); - // glDrawArrays(GL_LINE_STRIP, 0, length); -} - -//----------------------------------------------Unit testing------------------------------ /*! - * \brief Runs the Unit tests. - * \details Runs the Unit tests for the ConcavePolygon class. intersects() and pointInTriangle() are tested. + * \brief Draw the ConcavePolygon. + * \details This function actually draws the ConcavePolygon to the Canvas. + * \note This function overrides Drawable::draw() + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the ConcavePolygon cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). */ -void ConcavePolygon::runTests() { - TsglDebug("Testing ConcavePolygon class...."); - tsglAssert(testIntersects(), "Unit test for intersecting lines failed!"); - tsglAssert(testPointITriangle(), "Unit test for pointInTriangle() failed!"); - TsglDebug("Unit tests for ConcavePolygon complete."); - std::cout << std::endl; -} - -bool ConcavePolygon::testIntersects() { - int passed = 0; - int failed = 0; - ConcavePolygon c1(10); - - //Test 1: Intersecting lines - float x1, y1, x2, y2, x3, y3, x4, y4 = 0.0; - x1 = 230.0; //Set up the points so that it simulates two intersecting lines - y1 = 230.0; - x2 = 250.0; - y2 = 400.0; - x3 = 200.0; - y3 = 250.0; - x4 = 400.0; - y4 = 250.0; - - //They SHOULD intersect - if(c1.intersects(x1, y1, x2, y2, x3, y3, x4, y4)) { - passed++; - } else { - failed++; - TsglErr("Test 1, Intersecting lines for testIntersects() failed!"); - } - - x1 = y1 = x2 = y2 = x3 = y3 = x4 = y4 = 0.0; //Reset the x's and y's for the next test - - //Test 2: Parallel lines - x1 = 250.0; //Set up the points so that it simulates two parallel lines in the Canvas - y1 = 250.0; - x2 = 250.0; - y2 = 400.0; - x3 = 200.0; - y3 = 250.0; - x4 = 200.0; - y4 = 400.0; - - //They should NOT intersect, so if it returns false it passed - if(c1.intersects(x1, y1, x2, y2, x3, y3, x4, y4)) { - failed++; - TsglErr("Test 1, Parallel lines for testIntersects() failed!"); - } else { - passed++; - } - - //Results - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for intersecting lines passed!"); - return true; - } else { - TsglErr("This many passed for testIntersects(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testIntersects(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool ConcavePolygon::testPointITriangle() { - int passed = 0; - int failed = 0; - ConcavePolygon c2(10); - //Test 1: Point is in the triangle - float px, py, x1, y1, x2, y2, x3, y3 = 0.0; - - //Simulate a triangle and a point inside of it - x1 = 40.0; //Vertices... - y1 = 250.0; - x2 = 50.0; - y2 = 80.0; - x3 = 250.0; - y3 = 150.0; - px = 50.0; //Point coordinates... - py = 175.0; - - //Point SHOULD be in triangle - if(c2.pointInTriangle(px, py, x1, y1, x2, y2, x3, y3)) { - passed++; - } else { - failed++; - TsglErr("Test 1, Point = in triangle for testPointITriangle() failed!"); +void ConcavePolygon::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; } - - //Test 2: Point not in triangle - px = py = 0.0; //Reset the point - - px = 400.0; //Give it new coordinates - py = 400.0; - - //Point should NOT be in triangle, so it should return false - if(c2.pointInTriangle(px, py, x1, y1, x2, y2, x3, y3)) { - failed++; - TsglErr("Test 2, Point = NOT in triangle for testPointITriangle() failed!"); - } else { - passed++; + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + if (isFilled) { + /* extra stencil buffer stuff, because it's concave */ + glClearStencil(0); + glClear(GL_STENCIL_BUFFER); + glEnable(GL_STENCIL_TEST); + glDisable(GL_CULL_FACE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_NEVER, 0, 1); + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + /* end */ + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); + + /* extra stencil buffer stuff, because it's concave */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); + + glDisable(GL_STENCIL_TEST); } - //Results: - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for point in triangle passed!"); - return true; - } else { - TsglErr("This many passed for testPointITriangle(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testPointITriangle(): "); - std::cout << " " << failed << std::endl; - return false; + if (isOutlined) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfOutlineVertices * 7, outlineVertices, GL_DYNAMIC_DRAW); + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); } } -//---------------------------------------------End Unit testing----------------------- } diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index d6424f19b..c964a6c6d 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -5,7 +5,7 @@ #ifndef CONCAVEPOLYGON_H_ #define CONCAVEPOLYGON_H_ -#include "Polygon.h" // For extending our Shape object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes #include // std::queue #include // DEBUGGING @@ -22,47 +22,17 @@ namespace tsgl { * \note Calling addVertex() after all vertices have been added will do nothing. * \note Calling draw() before all vertices have been added will do nothing. */ -class ConcavePolygon : public Polygon { - private: - bool dirty; // Whether the new vertex buffer is dirty - int size, // Number of floating point numbers in vertices - tsize, // Number of floating point numbers in tarray - length; // Number of vertices in vertices (size / 6) - - void setup(int numVertices, bool filled, bool outlined = false); - - static bool testIntersects(); // Unit test for intersects() - static bool testPointITriangle(); // Unit test for pointInTriangle() - +class ConcavePolygon : public Shape { + protected: + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); public: - ConcavePolygon(int numVertices, bool filled = true, bool outlined = false); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); - - bool intersects(float p0_x, float p0_y, float p1_x, float p1_y, - float p2_x, float p2_y, float p3_x, float p3_y); - - bool pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3); - - void addVertex(float x, float y, const ColorFloat &color); - - void addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color); - void preprocess(); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]); - static void runTests(); + virtual void draw(Shader * shader); }; } -#endif /* COLOREDPOLYGON_H_ */ +#endif /* CONCAVEPOLYGON_H_ */ diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp new file mode 100644 index 000000000..2886ca755 --- /dev/null +++ b/src/TSGL/Cone.cpp @@ -0,0 +1,50 @@ +#include "Cone.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cone. + * \details Explicit constructor for a Cone object. + * \param x The x coordinate of the center of the Cone. + * \param y The y coordinate of the center of the Cone. + * \param z The z coordinate of the center of the Cone. + * \param height The distance from the center of the base to tip of the Cone. + * \param radius The radius of the Cone's circular base. + * \param yaw The Cone's yaw. + * \param pitch The Cone's pitch. + * \param roll The Cone's roll. + * \param c A ColorFloat for the Cone's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Cone with a buffer for storing the specified numbered of vertices. + */ +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices /= 2; +} + + /*! + * \brief Explicitly constructs a new Cone. + * \details Explicit constructor for a Cone object. + * \param x The x coordinate of the center of the Cone. + * \param y The y coordinate of the center of the Cone. + * \param z The z coordinate of the center of the Cone. + * \param height The distance from the center of the base to tip of the Cone. + * \param radius The radius of the Cone's circular base. + * \param yaw The Cone's yaw. + * \param pitch The Cone's pitch. + * \param roll The Cone's roll. + * \param c An array of ColorFloats containing the Cone's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Cone with a buffer for storing the specified numbered of vertices. + */ +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices /= 2; +} + +/*! + * \brief Destructor for the Cone. + */ +Cone::~Cone() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cone.h b/src/TSGL/Cone.h new file mode 100644 index 000000000..41bc3410a --- /dev/null +++ b/src/TSGL/Cone.h @@ -0,0 +1,29 @@ +/* + * Cone.h extends Pyramid and provides a class for drawing a cone. + */ + +#ifndef CONE_H_ +#define CONE_H_ + +#include "Pyramid.h" // For extending our Pyramid object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cone + * \brief Draw an arbitrary Cone with colored vertices. + * \details Cone is a class for holding vertex data for a cone. + * \details Cone is a subclass of Pyramid with a base of (radius * 3) sides, minimum of 3. + */ +class Cone : public Pyramid { +public: + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); + + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Cone(); +}; + +} + +#endif /* CONE_H_ */ \ No newline at end of file diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 4b78d5acb..36cf4a83d 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -4,201 +4,84 @@ namespace tsgl { /*! * \brief Explicitly constructs a new ConvexPolygon. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the complete ConvexPolygon will have. - * \param filled Whether or not the ConvexPolygon is filled. - * \param outlined Whether or not the ConvexPolygon is outlined. + * \details Protected explicit constructor for a Convex Polygon object. Used as superclass constructor. + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space.. * \return A new ConvexPolygon with a buffer for storing the specified numbered of vertices. */ -ConvexPolygon::ConvexPolygon(int numVertices, bool filled, bool outlined) : Polygon(numVertices) { - setup(numVertices, filled, outlined); -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with monocolored fill or outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color The color of the ConvexPolygon. - * \param filled Whether or not the ConvexPolygon is filled. - * (set to true by default). - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with multicolored fill or outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConvexPolygon. - * \param filled Whether or not the ConvexPolygon is filled. - * (set to true by default). - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with different monocolored fill and outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConvexPolygon's fill. - * \param outlineColor The color of the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with multicolored fill and monocolored outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConvexPolygon's fill. - * \param outlineColor The color of the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_FAN; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); } /*! - * \brief Explicitly constructs a new ConvexPolygon with monocolored fill and multicolored outline. + * \brief Explicitly constructs a new ConvexPolygon with monocolored fill. * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConvexPolygon's fill. - * \param outlineColor An array of colors for the ConvexPolygon's outline. + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param x An array of the ConvexPolygon's x vertices. + * \param y An array of the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space. + * \param color A ColorFloat, the ConvexPolygon's fill color. * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_FAN; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } /*! - * \brief Explicitly constructs a new ConvexPolygon with different multicolored fill and outline. + * \brief Explicitly constructs a new ConvexPolygon with multicolored fill. * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConvexPolygon's fill. - * \param outlineColor An array of colors for the ConvexPolygon's outline. + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param x An array of the ConvexPolygon's x vertices. + * \param y An array of the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConvexPolygon's fill color. * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); - } -} - -/*! - * \brief private helper method that works with the constructor - * \details Defines a lot of instance variables, initializes vertices and outlineVertices arrays - * \param numVertices Number of vertices on the ConvexPolygon - * \param filled Whether or not the ConvexPolygon is filled. - * \param outlined Whether or not the ConvexPolygon is outlined. - */ -void ConvexPolygon::setup(int numVertices, bool filled, bool outlined) { - numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices; - size = numberOfVertices * 6; - if(filled) { - vertices = new float[size]; - } - if(outlined) { - outlineVertices = new float[size]; - } +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - isFilled = filled; - hasOutline = outlined; -} - -/*! - * \brief Runs the Unit tests. - * \details Runs the Unit tests for the ConvexPolygon class. addVertex() is tested. - */ -void ConvexPolygon::runTests() { - TsglDebug("Testing ConvexPolygon class..."); - tsglAssert(testAddVertex(), "Unit test for adding vertices failed"); - TsglDebug("Unit tests for ConvexPolygon complete."); - std::cout << std::endl; -} - -bool ConvexPolygon::testAddVertex() { - int passed = 0; - int failed = 0; - ConvexPolygon c1(4); //Start with a polygon that has the capacity for four vertices - //Test 1: Adding a single vertex - if(c1.size == 24 && c1.current == 0) { //As it should be... - c1.addVertex(20, 30, BLACK); //Add a vertex; only the current should change... - if(c1.size == 24 && c1.current == 6) { - passed++; - } else { - failed++; - TsglErr("Test 1, One vertex for testAddVertex() failed!"); - } - } - - //Test 2: Filling the polygon vertices completely - //Add three more vertices, checking if the current has changed correspondingly - c1.addVertex(20, 30, BLACK); - c1.addVertex(20, 30, BLACK); - c1.addVertex(20, 30, BLACK); - - //The size should've remained the same but the current should now equal the size - if(c1.size == 24 && c1.current == 24) { - passed++; - } else { - failed++; - TsglErr("Test 2, Filling vertices completely for testAddVertex() failed!"); - } - - //Test 3: Attempting to add another vertex to a filled vertices.... - c1.addVertex(20, 30, BLACK); - //The size and current should've stayed the same - if(c1.size == 24 && c1.current == 24) { - passed++; - } else { - failed++; - TsglErr("Test 3, Add more beyond capacity for testAddVertex() failed!"); - } - - if(passed == 3 && failed == 0) { - TsglDebug("Unit test for adding vertices passed!"); - return true; - } else { - TsglErr("This many tests for ConvexPolygon passed: "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests for ConvexPolygon failed: "); - std::cout << " " << failed << std::endl; - return false; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; + vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); + for (int i = 0; i < numVertices; i++) { + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } diff --git a/src/TSGL/ConvexPolygon.h b/src/TSGL/ConvexPolygon.h index f13f74792..0bab85d15 100755 --- a/src/TSGL/ConvexPolygon.h +++ b/src/TSGL/ConvexPolygon.h @@ -5,7 +5,7 @@ #ifndef CONVEXPOLYGON_H_ #define CONVEXPOLYGON_H_ -#include "Polygon.h" // For extending our Shape object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -20,29 +20,13 @@ namespace tsgl { * \note Calling addVertex() after all vertices have been added will do nothing. * \note Calling draw() before all vertices have been added will do nothing. */ -class ConvexPolygon : public Polygon { - private: - int size; - - static bool testAddVertex(); // Unit test for addVertex() +class ConvexPolygon : public Shape { + protected: + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); public: - ConvexPolygon(int numVertices, bool filled = true, bool outlined = false); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); - - void setup(int numVertices, bool filled, bool outlined); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color); - static void runTests(); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]); }; } diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp new file mode 100644 index 000000000..03e9f25ce --- /dev/null +++ b/src/TSGL/Cube.cpp @@ -0,0 +1,311 @@ +#include "Cube.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cube. + * \details Explicit constructor for a Cube object. + * \param x The x coordinate of the center of the Cube. + * \param y The y coordinate of the center of the Cube. + * \param z The z coordinate of the center of the Cube. + * \param sideLength The side length of the Cube. + * \param yaw The Cube's yaw, in degrees. + * \param pitch The Cube's pitch, in degrees. + * \param roll The Cube's roll, in degrees. + * \param c A ColorFloat for the Cube's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cube with a buffer for storing the specified numbered of vertices. + */ +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c) +: Shape(x, y, z, yaw, pitch, roll) { + if (sideLength <= 0) { + TsglDebug("Cannot have a Cube with non-positive sidelength."); + } + attribMutex.lock(); + geometryType = GL_TRIANGLES; + mySideLength = sideLength; + myXScale = sideLength; + myYScale = sideLength; + myZScale = sideLength; + numberOfVertices = 36; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); +} + + /*! + * \brief Explicitly constructs a new Cube. + * \details Explicit constructor for a Cube object. + * \param x The x coordinate of the center of the Cube. + * \param y The y coordinate of the center of the Cube. + * \param z The z coordinate of the center of the Cube. + * \param sideLength The side length of the Cube. + * \param yaw The Cube's yaw, in degrees. + * \param pitch The Cube's pitch, in degrees. + * \param roll The Cube's roll, in degrees. + * \param c An array of ColorFloats for the Cube's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cube with a buffer for storing the specified numbered of vertices. + */ +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c[]) +: Shape(x, y, z, yaw, pitch, roll) { + if (sideLength <= 0) { + TsglDebug("Cannot have a Cube with non-positive sidelength."); + } + attribMutex.lock(); + geometryType = GL_TRIANGLES; + mySideLength = sideLength; + myXScale = sideLength; + myYScale = sideLength; + myZScale = sideLength; + numberOfVertices = 36; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, 0.5, -0.5, c[3]); + + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, 0.5, c[5]); + + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, 0.5, c[5]); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); +} + +/** + * \brief Mutates the distance between the Cube's opposite faces. + * \param length The Cube's new side length. + */ +void Cube::setSideLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have a Cube with side length less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = length; + myYScale = length; + myZScale = length; + mySideLength = length; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cube's front face to its back face by the parameter amount. + * \param delta The amount by which to change the length of the Cube. + */ +void Cube::changeSideLengthBy(GLfloat delta) { + if (mySideLength + delta <= 0) { + TsglDebug("Cannot have a Cube with length less than or equal to 0."); + return; + } + attribMutex.lock(); + mySideLength += delta; + myXScale += delta; + myYScale += delta; + myZScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Sets the Cube to an array of new colors. + * \param c An array of new ColorFloats. + * \details The array should have 8 ColorFloats minimum, one for each corner. + */ +void Cube::setColor(ColorFloat c[]) { + attribMutex.lock(); + vertices[3] = vertices[24] = vertices[94] = vertices[171] = vertices[192] = c[0].R; + vertices[4] = vertices[25] = vertices[95] = vertices[172] = vertices[193] = c[0].G; + vertices[5] = vertices[26] = vertices[96] = vertices[173] = vertices[194] = c[0].B; + vertices[6] = vertices[27] = vertices[97] = vertices[174] = vertices[195] = c[0].A; + + vertices[10] = vertices[101] = vertices[115] = vertices[213] = vertices[234] = c[1].R; + vertices[11] = vertices[102] = vertices[116] = vertices[214] = vertices[235] = c[1].G; + vertices[12] = vertices[103] = vertices[117] = vertices[215] = vertices[236] = c[1].B; + vertices[13] = vertices[104] = vertices[118] = vertices[216] = vertices[237] = c[1].A; + + vertices[17] = vertices[31] = vertices[143] = vertices[157] = vertices[220] = c[2].R; + vertices[18] = vertices[32] = vertices[144] = vertices[158] = vertices[221] = c[2].G; + vertices[19] = vertices[33] = vertices[145] = vertices[159] = vertices[222] = c[2].B; + vertices[20] = vertices[34] = vertices[146] = vertices[160] = vertices[223] = c[2].A; + + vertices[38] = vertices[136] = vertices[178] = c[3].R; + vertices[39] = vertices[137] = vertices[179] = c[3].G; + vertices[40] = vertices[138] = vertices[180] = c[3].B; + vertices[41] = vertices[139] = vertices[181] = c[3].A; + + vertices[45] = vertices[66] = vertices[87] = vertices[108] = vertices[206] = c[4].R; + vertices[46] = vertices[67] = vertices[88] = vertices[109] = vertices[207] = c[4].G; + vertices[47] = vertices[68] = vertices[89] = vertices[110] = vertices[208] = c[4].B; + vertices[48] = vertices[69] = vertices[90] = vertices[111] = vertices[209] = c[4].A; + + vertices[52] = vertices[122] = vertices[248] = c[5].R; + vertices[53] = vertices[123] = vertices[249] = c[5].G; + vertices[54] = vertices[124] = vertices[250] = c[5].B; + vertices[55] = vertices[125] = vertices[251] = c[5].A; + + vertices[59] = vertices[73] = vertices[164] = vertices[227] = vertices[241] = c[6].R; + vertices[60] = vertices[74] = vertices[165] = vertices[228] = vertices[242] = c[6].G; + vertices[61] = vertices[75] = vertices[166] = vertices[229] = vertices[243] = c[6].B; + vertices[62] = vertices[76] = vertices[167] = vertices[230] = vertices[244] = c[6].A; + + vertices[80] = vertices[129] = vertices[150] = vertices[185] = vertices[199] = c[7].R; + vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; + vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; + vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; + + myAlpha = (c[0].A + c[1].A + c[2].A + c[3].A + c[4].A + c[5].A + c[6].A + c[7].A) / 8; + attribMutex.unlock(); +} + +/** + * \brief Accessor for Cube's colors. + * \details Populates the reference parameter vector with a ColorFloat for each corner of Cube. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Cube will be pushed. + * \note Overrides Shape::getColors(). + */ +void Cube::getColors(std::vector &colorVec) { + attribMutex.lock(); + colorVec.push_back(ColorFloat(vertices[3],vertices[4],vertices[5],vertices[6])); + colorVec.push_back(ColorFloat(vertices[10],vertices[11],vertices[12],vertices[13])); + colorVec.push_back(ColorFloat(vertices[17],vertices[18],vertices[19],vertices[20])); + colorVec.push_back(ColorFloat(vertices[38],vertices[39],vertices[40],vertices[41])); + colorVec.push_back(ColorFloat(vertices[45],vertices[46],vertices[47],vertices[48])); + colorVec.push_back(ColorFloat(vertices[52],vertices[53],vertices[54],vertices[55])); + colorVec.push_back(ColorFloat(vertices[59],vertices[60],vertices[61],vertices[62])); + colorVec.push_back(ColorFloat(vertices[80],vertices[81],vertices[82],vertices[83])); + attribMutex.unlock(); +} + +} \ No newline at end of file diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h new file mode 100644 index 000000000..e0a6f8743 --- /dev/null +++ b/src/TSGL/Cube.h @@ -0,0 +1,50 @@ +/* + * Cube.h extends Shape and provides a class for drawing a Cube. + */ + +#ifndef CUBE_H_ +#define CUBE_H_ + +#include "Shape.h" // For extending our Shape object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cube + * \brief Draw an arbitrary Cube with colored vertices. + * \details Cube is a class for holding vertex data for a Cube. + * \details Cube is a 6-sided subclass of Shape with all square faces. + */ +class Cube : public Shape { +protected: + GLfloat mySideLength; +public: + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c); + + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setSideLength(float length); + + virtual void changeSideLengthBy(float delta); + + /*! + * \brief Accessor for the side length of the Cube. + * \details Returns the value of the mySideLength private variable, a GLfloat. + */ + virtual GLfloat getSideLength() { return mySideLength; } + + virtual void setColor(ColorFloat c) { Shape::setColor(c); } + + virtual void setColor(ColorFloat c[]); + + virtual void getColors(std::vector &colorVec); + + /*! + * \brief Destructor for the Cube. + */ + virtual ~Cube() {} +}; + +} + +#endif /* CUBE_H_ */ \ No newline at end of file diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp new file mode 100644 index 000000000..7cc61ccbd --- /dev/null +++ b/src/TSGL/Cuboid.cpp @@ -0,0 +1,374 @@ +#include "Cuboid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cuboid. + * \details Explicit constructor for a Cuboid object. + * \param x The x coordinate of the center of the Cuboid. + * \param y The y coordinate of the center of the Cuboid. + * \param z The z coordinate of the center of the Cuboid. + * \param length The length of the Cuboid. + * \param width The width of the Cuboid. + * \param height The height of the Cuboid. + * \param yaw The Cuboid's yaw. + * \param pitch The Cuboid's pitch. + * \param roll The Cuboid's roll. + * \param c A ColorFloat for the Cuboid's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cuboid with a buffer for storing the specified numbered of vertices. + */ +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c) +: Shape(x, y, z, yaw, pitch, roll) { + if (length <= 0 || width <= 0 || height <= 0) { + TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); + } + attribMutex.lock(); + geometryType = GL_TRIANGLES; + myLength = length; + myWidth = width; + myHeight = height; + myXScale = width; + myYScale = height; + myZScale = length; + numberOfVertices = 36; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); +} + + /*! + * \brief Explicitly constructs a new Cuboid. + * \details Explicit constructor for a Cuboid object. + * \param x The x coordinate of the center of the Cuboid. + * \param y The y coordinate of the center of the Cuboid. + * \param z The z coordinate of the center of the Cuboid. + * \param length The length of the Cuboid. + * \param width The width of the Cuboid. + * \param height The height of the Cuboid. + * \param yaw The Cuboid's yaw. + * \param pitch The Cuboid's pitch. + * \param roll The Cuboid's roll. + * \param c An array of ColorFloats for the Cuboid's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cuboid with a buffer for storing the specified numbered of vertices. + */ +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c[]) +: Shape(x, y, z, yaw, pitch, roll) { + if (length <= 0 || width <= 0 || height <= 0) { + TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); + } + attribMutex.lock(); + geometryType = GL_TRIANGLES; + myLength = length; + myWidth = width; + myHeight = height; + myXScale = width; + myYScale = height; + myZScale = length; + numberOfVertices = 36; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, 0.5, -0.5, c[3]); + + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, 0.5, c[5]); + + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, 0.5, c[5]); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); +} + +/** + * \brief Mutates the distance from the Cuboid's front face to its back face. + * \param height The Cuboid's new length. + */ +void Cuboid::setLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); + return; + } + attribMutex.lock(); + myLength = length; + myZScale = length; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's front face to its back face by the parameter amount. + * \param delta The amount by which to change the length of the Cuboid. + */ +void Cuboid::changeLengthBy(GLfloat delta) { + if (myLength + delta <= 0) { + TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); + return; + } + attribMutex.lock(); + myLength += delta; + myZScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's left face to its right face. + * \param height The Cuboid's new width. + */ +void Cuboid::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = width; + myXScale = width; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's left face to its right face by the parameter amount. + * \param delta The amount by which to change the width of the Cuboid. + */ +void Cuboid::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth += delta; + myXScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cuboid's base to the top. + * \param height The Cuboid's new height. + */ +void Cuboid::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight = height; + myYScale = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cuboid's base to the top by the parameter amount. + * \param delta The amount by which to change the height of the Cuboid. + */ +void Cuboid::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Sets the Cuboid to an array of new colors. + * \param c An array of new ColorFloats. + * \details The array should have 8 ColorFloats minimum, one for each corner. + */ +void Cuboid::setColor(ColorFloat c[]) { + attribMutex.lock(); + vertices[3] = vertices[24] = vertices[94] = vertices[171] = vertices[192] = c[0].R; + vertices[4] = vertices[25] = vertices[95] = vertices[172] = vertices[193] = c[0].G; + vertices[5] = vertices[26] = vertices[96] = vertices[173] = vertices[194] = c[0].B; + vertices[6] = vertices[27] = vertices[97] = vertices[174] = vertices[195] = c[0].A; + + vertices[10] = vertices[101] = vertices[115] = vertices[213] = vertices[234] = c[1].R; + vertices[11] = vertices[102] = vertices[116] = vertices[214] = vertices[235] = c[1].G; + vertices[12] = vertices[103] = vertices[117] = vertices[215] = vertices[236] = c[1].B; + vertices[13] = vertices[104] = vertices[118] = vertices[216] = vertices[237] = c[1].A; + + vertices[17] = vertices[31] = vertices[143] = vertices[157] = vertices[220] = c[2].R; + vertices[18] = vertices[32] = vertices[144] = vertices[158] = vertices[221] = c[2].G; + vertices[19] = vertices[33] = vertices[145] = vertices[159] = vertices[222] = c[2].B; + vertices[20] = vertices[34] = vertices[146] = vertices[160] = vertices[223] = c[2].A; + + vertices[38] = vertices[136] = vertices[178] = c[3].R; + vertices[39] = vertices[137] = vertices[179] = c[3].G; + vertices[40] = vertices[138] = vertices[180] = c[3].B; + vertices[41] = vertices[139] = vertices[181] = c[3].A; + + vertices[45] = vertices[66] = vertices[87] = vertices[108] = vertices[206] = c[4].R; + vertices[46] = vertices[67] = vertices[88] = vertices[109] = vertices[207] = c[4].G; + vertices[47] = vertices[68] = vertices[89] = vertices[110] = vertices[208] = c[4].B; + vertices[48] = vertices[69] = vertices[90] = vertices[111] = vertices[209] = c[4].A; + + vertices[52] = vertices[122] = vertices[248] = c[5].R; + vertices[53] = vertices[123] = vertices[249] = c[5].G; + vertices[54] = vertices[124] = vertices[250] = c[5].B; + vertices[55] = vertices[125] = vertices[251] = c[5].A; + + vertices[59] = vertices[73] = vertices[164] = vertices[227] = vertices[241] = c[6].R; + vertices[60] = vertices[74] = vertices[165] = vertices[228] = vertices[242] = c[6].G; + vertices[61] = vertices[75] = vertices[166] = vertices[229] = vertices[243] = c[6].B; + vertices[62] = vertices[76] = vertices[167] = vertices[230] = vertices[244] = c[6].A; + + vertices[80] = vertices[129] = vertices[150] = vertices[185] = vertices[199] = c[7].R; + vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; + vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; + vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; + myAlpha = (c[0].A + c[1].A + c[2].A + c[3].A + c[4].A + c[5].A + c[6].A + c[7].A) / 8; + attribMutex.unlock(); +} + +/** + * \brief Accessor for Cuboid's colors. + * \details Populates the reference parameter vector with a ColorFloat for each corner of Cuboid. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Cuboid will be pushed. + * \note Overrides Shape::getColors(). + */ +void Cuboid::getColors(std::vector &colorVec) { + attribMutex.lock(); + colorVec.push_back(ColorFloat(vertices[3],vertices[4],vertices[5],vertices[6])); + colorVec.push_back(ColorFloat(vertices[10],vertices[11],vertices[12],vertices[13])); + colorVec.push_back(ColorFloat(vertices[17],vertices[18],vertices[19],vertices[20])); + colorVec.push_back(ColorFloat(vertices[38],vertices[39],vertices[40],vertices[41])); + colorVec.push_back(ColorFloat(vertices[45],vertices[46],vertices[47],vertices[48])); + colorVec.push_back(ColorFloat(vertices[52],vertices[53],vertices[54],vertices[55])); + colorVec.push_back(ColorFloat(vertices[59],vertices[60],vertices[61],vertices[62])); + colorVec.push_back(ColorFloat(vertices[80],vertices[81],vertices[82],vertices[83])); + attribMutex.unlock(); +} + +} \ No newline at end of file diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h new file mode 100644 index 000000000..a95afbe69 --- /dev/null +++ b/src/TSGL/Cuboid.h @@ -0,0 +1,65 @@ +/* + * Cuboid.h extends Prism and provides a class for drawing a Cuboid. + */ + +#ifndef CUBOID_H_ +#define CUBOID_H_ + +#include "Shape.h" // For extending our Prism object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cuboid + * \brief Draw an arbitrary Cuboid with colored vertices. + * \details Cuboid is a class for holding vertex data for a Cuboid. + * \details Cuboid is a 6-sided subclass of Shape with all rectangular faces. + */ +class Cuboid : public Shape { +protected: + GLfloat myLength, myWidth, myHeight; +public: + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c); + + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setLength(GLfloat length); + + virtual void changeLengthBy(GLfloat delta); + + virtual void setWidth(GLfloat width); + + virtual void changeWidthBy(GLfloat delta); + + virtual void setHeight(GLfloat height); + + virtual void changeHeightBy(GLfloat delta); + + /*! + * \brief Accessor for the length of the Prism. + * \details Returns the value of the myLength private variable, a GLfloat. + */ + virtual GLfloat getLength() { return myLength; } + + /*! + * \brief Accessor for the height of the Prism. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ + virtual GLfloat getHeight() { return myHeight; } + + /*! + * \brief Accessor for the width of the Prism. + * \details Returns the value of the myWidth private variable, a GLfloat. + */ + virtual GLfloat getWidth() { return myWidth; } + + virtual void setColor(ColorFloat c) { Shape::setColor(c); } + + virtual void setColor(ColorFloat c[]); + + virtual void getColors(std::vector &colorVec); +}; + +} + +#endif /* CUBOID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp new file mode 100644 index 000000000..c901726a5 --- /dev/null +++ b/src/TSGL/Cylinder.cpp @@ -0,0 +1,50 @@ +#include "Cylinder.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cylinder. + * \details Explicit constructor for a Cylinder object. + * \param x The x coordinate of the center of the Cylinder. + * \param y The y coordinate of the center of the Cylinder. + * \param z The z coordinate of the center of the Cylinder. + * \param height The height of the Cylinder. + * \param radius The radius of the Cylinder's circular base. + * \param yaw The Cylinder's yaw. + * \param pitch The Cylinder's pitch. + * \param roll The Cylinder's roll. + * \param c A ColorFloat for the Cylinder's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cylinder with a buffer for storing the specified numbered of vertices. + */ +Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) +: Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices = numberOfOutlineVertices * 2 / 3; +} + + /*! + * \brief Explicitly constructs a new Cylinder. + * \details Explicit constructor for a Cylinder object. + * \param x The x coordinate of the center of the Cylinder. + * \param y The y coordinate of the center of the Cylinder. + * \param z The z coordinate of the center of the Cylinder. + * \param height The height of the Cylinder. + * \param radius The radius of the Cylinder's circular base. + * \param yaw The Cylinder's yaw. + * \param pitch The Cylinder's pitch. + * \param roll The Cylinder's roll. + * \param c An array of ColorFloats for the Cylinder's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cylinder with a buffer for storing the specified numbered of vertices. + */ +Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) +: Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices = numberOfOutlineVertices * 2 / 3; +} + +/*! + * \brief Destructor for the Cylinder. + */ +Cylinder::~Cylinder() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cylinder.h b/src/TSGL/Cylinder.h new file mode 100644 index 000000000..1c37903ef --- /dev/null +++ b/src/TSGL/Cylinder.h @@ -0,0 +1,29 @@ +/* + * Cylinder.h extends Prism and provides a class for drawing a Cylinder. + */ + +#ifndef CYLINDER_H_ +#define CYLINDER_H_ + +#include "Prism.h" // For extending our Prism object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cylinder + * \brief Draw an arbitrary Cylinder with colored vertices. + * \details Cylinder is a class for holding vertex data for a Cylinder. + * \details Cylinder is a subclass of Prism with a circular base. + */ +class Cylinder : public Prism { +public: + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c); + + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Cylinder(); +}; + +} + +#endif /* CYLINDER_H_ */ \ No newline at end of file diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index 5f78d790d..1e85658bb 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -4,57 +4,372 @@ namespace tsgl { /*! * \brief Constructs a new Drawable. + * \details + * - Usually vertices is filled with floating point values that represent the vertices of the Drawable to be drawn. + * - You may define other items in the constructor that pertain to the attributes of the subclass that is extending Drawable. + * - At a minimum, you *MUST* fill an array of floating point values that pertain to the vertices of the Drawable. * \warning You must inherit the parent's constructor if you are extending Drawable. * \note Refer to the Drawable class description for more details. */ -Drawable::Drawable() { +Drawable::Drawable(float x, float y, float z, float yaw, float pitch, float roll) { + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + myCenterX = x; + myCenterY = y; + myCenterZ = z; + myRotationPointX = myCenterX; + myRotationPointY = myCenterY; + myRotationPointZ = myCenterZ; +} + +///////////////////////////////////////////////// +// MUTATORS +///////////////////////////////////////////////// + + +/** + * \brief Alters the Drawable's x position + * \param deltaX The difference between the new and old vertex x coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeXBy(float deltaX) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX += deltaX; + } + myCenterX += deltaX; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's y position + * \param deltaY The difference between the new and old vertex y coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeYBy(float deltaY) { attribMutex.lock(); - renderLayer = -1; + if (centerMatchesRotationPoint()) { + myRotationPointY += deltaY; + } + myCenterY += deltaY; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's z position + * \param deltaZ The difference between the new and old vertex z coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeZBy(float deltaZ) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointZ += deltaZ; + } + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's vertex locations. + * \param deltaX The difference between the new and old vertex x coordinates. + * \param deltaY The difference between the new and old vertex y coordinates. + * \param deltaZ The difference between the new and old vertex z coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeCenterBy(float deltaX, float deltaY, float deltaZ) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX += deltaX; + myRotationPointY += deltaY; + myRotationPointZ += deltaZ; + } + myCenterX += deltaX; + myCenterY += deltaY; + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's x position + * \param x The new center x coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterX(float x) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX = x; + } + myCenterX = x; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's y position + * \param y The new center y coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterY(float y) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointY = y; + } + myCenterY = y; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's z position + * \param z The new center z coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterZ(float z) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointZ = z; + } + myCenterZ = z; + attribMutex.unlock(); +} + +/** + * \brief Moves the Drawable to new coordinates. + * \param x The new center x coordinate. + * \param y The new center y coordinate. + * \param z The new center z coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenter(float x, float y, float z) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX = x; + myRotationPointY = y; + myRotationPointZ = z; + } + myCenterX = x; + myCenterY = y; + myCenterZ = z; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Drawable's yaw + * \param yaw The new yaw value for Drawable. + */ +void Drawable::setYaw(float yaw) { + attribMutex.lock(); + myCurrentYaw = yaw; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Drawable's pitch + * \param pitch The new pitch value for Drawable. + */ +void Drawable::setPitch(float pitch) { + attribMutex.lock(); + myCurrentPitch = pitch; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Drawable's roll + * \param roll The new roll value for Drawable. + */ +void Drawable::setRoll(float roll) { + attribMutex.lock(); + myCurrentRoll = roll; attribMutex.unlock(); } /*! - * \brief Accessor for isTextured. - * \return Whether the drawable is a textured primitive or not. + * \brief Mutator for the yaw, pitch, and roll of the Drawable. + * \param yaw The new yaw value for Drawable. + * \param pitch The new pitch value for Drawable. + * \param roll The new roll value for Drawable. + */ +void Drawable::setYawPitchRoll(float yaw, float pitch, float roll) { + attribMutex.lock(); + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's yaw by a specified amount. + * \param deltaYaw The change in yaw value for Drawable. + */ +void Drawable::changeYawBy(float deltaYaw) { + attribMutex.lock(); + myCurrentYaw += deltaYaw; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's pitch by a specified amount. + * \param deltaPitch The change in pitch value for Drawable. */ -bool Drawable::getIsTextured() { +void Drawable::changePitchBy(float deltaPitch) { attribMutex.lock(); - bool retVal = isTextured; + myCurrentPitch += deltaPitch; attribMutex.unlock(); - return retVal; } /** -* \brief Sets the layer of the Drawable. -* \param n The new layer of the Drawable. -* \details Sets renderLayer to n if n >= 0. -*/ -void Drawable::setLayer(int n) { + * \brief Alters the Drawable's roll by a specified amount. + * \param deltaRoll The change in roll value for Drawable. + */ +void Drawable::changeRollBy(float deltaRoll) { attribMutex.lock(); - if (n>=0) { renderLayer = n; } + myCurrentRoll += deltaRoll; attribMutex.unlock(); } /** - * \brief Accessor for renderLayer. - * \return The layer the drawable is set at. + * \brief Alters the Drawable's yaw, pitch, and roll by a specified amount. + * \param deltaYaw The change in yaw value for Drawable. + * \param deltaPitch The change in pitch value for Drawable. + * \param deltaRoll The change in roll value for Drawable. */ -int Drawable::getLayer() { +void Drawable::changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll) { attribMutex.lock(); - int retVal = renderLayer; + myCurrentYaw += deltaYaw; + myCurrentPitch += deltaPitch; + myCurrentRoll += deltaRoll; attribMutex.unlock(); - return retVal; } /*! - * \brief Virtual mutator that changes the rotation point of the Drawable - * \details Alters myRotationPointX and myRotationPointY; - * \param x myRotationPointX's new float value. + * \brief Virtual mutator that changes the rotation point of the Drawable's x value. + * \details Alters myRotationPointX; + * \param z myRotationPointX's new float value. + */ +void Drawable::setRotationPointX(float x) { + attribMutex.lock(); + myRotationPointX = x; + attribMutex.unlock(); +} + +/*! + * \brief Virtual mutator that changes the rotation point of the Drawable's y value. + * \details Alters myRotationPointY; * \param y myRotationPointY's new float value. */ -void Drawable::setRotationPoint(float x, float y) { +void Drawable::setRotationPointY(float y) { + attribMutex.lock(); + myRotationPointY = y; + attribMutex.unlock(); +} + +/*! + * \brief Virtual mutator that changes the rotation point of the Drawable's z value. + * \details Alters myRotationPointZ; + * \param z myRotationPointZ's new float value. + */ +void Drawable::setRotationPointZ(float z) { + attribMutex.lock(); + myRotationPointZ = z; + attribMutex.unlock(); +} + +/** + * \brief Sets the point around which Drawable is rotated. + * \param x The x coordinate of the new rotation point. + * \param y The y coordinate of the new rotation point. + * \param z The z coordinate of the new rotation point. + */ +void Drawable::setRotationPoint(float x, float y, float z) { + attribMutex.lock(); myRotationPointX = x; myRotationPointY = y; + myRotationPointZ = z; + attribMutex.unlock(); +} + +/*! + * \brief Accessor for the center x-coordinate of the Drawable. + * \details Returns the value of the myCenterX private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointX; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterX() { + attribMutex.lock(); + float cx; + if (centerMatchesRotationPoint()) { + cx = myCenterX; + attribMutex.unlock(); + return cx; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + cx = cosYaw * cosPitch * (myCenterX - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myCenterY - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointX; + attribMutex.unlock(); + return cx; +} + +/*! + * \brief Accessor for the center z-coordinate of the Drawable. + * \details Returns the value of the myCenterY private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointY; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterY() { + attribMutex.lock(); + float cy; + if (centerMatchesRotationPoint()) { + cy = myCenterY; + attribMutex.unlock(); + return cy; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + cy = sinYaw * cosPitch * (myCenterX - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myCenterY - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointY; + attribMutex.unlock(); + return cy; +} + +/*! + * \brief Accessor for the center z-coordinate of the Drawable. + * \details Returns the value of the myCenterZ private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointZ; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterZ() { + attribMutex.lock(); + float cz; + if (centerMatchesRotationPoint()) { + cz = myCenterZ; + attribMutex.unlock(); + return cz; + } + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + cz = -sinPitch * (myCenterX - myRotationPointX) + cosPitch * sinRoll * (myCenterY - myRotationPointY) + cosPitch * cosRoll * (myCenterZ - myRotationPointZ) + myRotationPointZ; + attribMutex.unlock(); + return cz; +} + +Drawable::~Drawable() { + delete[] vertices; } } \ No newline at end of file diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 30bf34ec2..b4f437dde 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -1,85 +1,142 @@ /* -* Drawable.h provides a base class from which to extend other drawable shapes. -*/ + * Drawable.h provides a base class from which to extend other drawable objects. + */ #ifndef DRAWABLE_H_ #define DRAWABLE_H_ -#include // Needed for locking the attribute mutex for thread-safety #include "Color.h" // Needed for color type +#include "Shader.h" +#include +#include +#include +#include // Needed for locking the attribute mutex for thread-safety namespace tsgl { - /*! \class Drawable - * \brief A class for drawing onto a Canvas or CartesianCanvas. - * \details Drawable provides a base class for drawing a shape, text, or image to a Canvas or CartesianCanvas. - * \note Drawable is abstract and must be extended. - */ - class Drawable { - protected: - std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed - bool isTextured = false; ///< Whether the Drawable is a Textured object. - float myRotationPointX, myRotationPointY, myCenterX, myCenterY; - int renderLayer; // The depth index to control the drawing order of the shapes - public: - Drawable(); +/*! \class Drawable + * \brief A class for drawing objects onto a Canvas or CartesianCanvas. + * \warning Though extending this class must be allowed due to the way the code is set up, attempting to do so + * could potentially mess up the internal GL calls the library uses. Proceed with great caution. + * \details Drawable provides a base class for drawing 3D objects to a Canvas or CartesianCanvas. + * \note Drawable is abstract, and must be extended by the user. + * \details vertices should be an array of floating point values in TSGL's vertex format. + * \details numberofvertices should be the actual integer number of vertices to be drawn (e.g., *36* for a cube). + * \details geometryType should be one of GL's primitive drawing modes. + * See https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml for further information. + * \details Theoretically, you could potentially extend the Drawable class so that you can create another Drawable class that suits your needs. + * \details However, this is not recommended for normal use of the TSGL library. + */ +class Drawable { + protected: + std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed + GLfloat* vertices; + float myCurrentYaw, myCurrentPitch, myCurrentRoll; + float myXScale, myYScale, myZScale; + float myRotationPointX, myRotationPointY, myRotationPointZ; + float myCenterX, myCenterY, myCenterZ; + bool init = false; + unsigned int shaderType = SHAPE_SHADER_TYPE; + GLfloat myAlpha = 0.0; + /*! + * \brief Protected helper method that determines if the Drawable's center matches its rotation point. + * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ + * \return True if all three coordinates match their respective others, false otherwise. + */ + bool centerMatchesRotationPoint() { + return (myCenterX == myRotationPointX && myCenterY == myRotationPointY && myCenterZ == myRotationPointZ); + } + public: + Drawable(float x, float y, float z, float yaw, float pitch, float roll); + + virtual ~Drawable(); + + virtual void draw(Shader * shader) = 0; + + virtual void changeXBy(float deltaX); + virtual void changeYBy(float deltaY); + virtual void changeZBy(float deltaZ); + virtual void changeCenterBy(float deltaX, float deltaY, float deltaZ); + + virtual void setCenterX(float x); + virtual void setCenterY(float y); + virtual void setCenterZ(float z); + virtual void setCenter(float x, float y, float z); + + virtual void setYaw(float yaw); + virtual void setPitch(float pitch); + virtual void setRoll(float roll); + virtual void setYawPitchRoll(float yaw, float pitch, float roll); + + virtual void changeYawBy(float deltaYaw); + virtual void changePitchBy(float deltaPitch); + virtual void changeRollBy(float deltaRoll); + virtual void changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll); + + virtual void setRotationPointX(float x); + virtual void setRotationPointY(float y); + virtual void setRotationPointZ(float z); + virtual void setRotationPoint(float x, float y, float z); + + virtual float getCenterX(); + virtual float getCenterY(); + virtual float getCenterZ(); /*! - * \brief Destroys the Drawable. - * \details Destructor for a Drawable. - * \details Frees up memory that was allocated to a Drawable object. + * \brief Accessor for the Yaw of the Drawable. + * \details Returns the value of the myCurrentYaw private variable. */ - virtual ~Drawable() { } + virtual float getYaw() { return myCurrentYaw; } /*! - * \brief Actually draws the Drawable to the Canvas. - * \details This method renders the drawable to the Canvas. - * - When you extend the Drawable class, you *MUST* provide a definition for this method. - * - The definition must follow this format: - * - * glBufferData(drawingMode, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - * glDrawArrays(drawingMode, 0, numberOfVertices); - * - * - Really bad things could potentially happen if you do not follow this format. These two statements *MUST* be - * in the draw() method of the subclass that extends the Drawable class. - * - You can add other statements in the subclass - * \note Please refer to the class description for more information and warnings about overriding this method. - */ - virtual void draw() = 0; // Abstract method for actually drawing the shape - - bool getIsTextured(); - - void setLayer(int n); - - int getLayer(); - - /*! - * \brief Virtual accessor that returns if Drawable is processed and ready to be drawn - * \details This function returns true only if all vertices have been inserted into an array. + * \brief Accessor for the Pitch of the Drawable. + * \details Returns the value of the myCurrentPitch private variable. */ - virtual bool isProcessed() { return true; } + virtual float getPitch() { return myCurrentPitch; } /*! - * \brief Pure virtual mutator that changes the rotation of the Drawable - * \details Rotates the Drawable clockwise by radians radians. - * \param radians The number of radians to rotate the Drawable. - */ - virtual void setRotation(float radians) = 0; - - virtual void setRotationPoint(float x, float y); + * \brief Accessor for the Roll of the Drawable. + * \details Returns the value of the myCurrentRoll private variable. + */ + virtual float getRoll() { return myCurrentRoll; } /*! - * \brief Accessor for the center x-coordinate of the Drawable. - * \details Returns the value of the myCenterX private variable. + * \brief Accessor for the rotation x-coordinate of the Drawable. + * \details Returns the value of the myRotationPointX private variable. */ - virtual float getCenterX() { return myCenterX; } + virtual float getRotationPointX() { return myRotationPointX; } /*! - * \brief Accessor for the center y-coordinate of the Drawable. - * \details Returns the value of the myCenterY private variable. + * \brief Accessor for the rotation y-coordinate of the Drawable. + * \details Returns the value of the myRotationPointY private variable. */ - virtual float getCenterY() { return myCenterY; } - }; + virtual float getRotationPointY() { return myRotationPointY; } + + /*! + * \brief Accessor for the rotation z-coordinate of the Drawable. + * \details Returns the value of the myRotationPointZ private variable. + */ + virtual float getRotationPointZ() { return myRotationPointZ; } + + /*! + * \brief Accessor that returns if Drawable is processed and ready to be drawn + * \details This function returns true only if all vertices have been inserted into an array. + */ + virtual bool isProcessed() { return init; } + + /*! + * \brief Accessor that returns a value corresponding to a certain shader in Canvas. + * \details This function returns the value of the shaderType instance variable. + */ + virtual unsigned int getShaderType() { return shaderType; } + + /*! + * \brief Accessor that returns Drawable's alpha value. + * \details Principally designed to be used within Canvas for transparency sorting. + */ + virtual float getAlpha() { return myAlpha; } }; -#endif /* DRAWABLE_H_ */ \ No newline at end of file +} + +#endif /* DRAWABLE_H_ */ diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index fa9e7d76f..b31dcecdf 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -3,114 +3,160 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new monocolored filled or outlined Ellipse. - * \details This function draws a Ellipse with the given center, radii, color, and outline color. + * \brief Explicitly constructs a new monocolored Ellipse. + * \details This function draws a Ellipse with the given center, radii, rotation, and color. * \param x The x coordinate of the Ellipse's center. * \param y The y coordinate of the Ellipse's center. + * \param z The z coordinate of the Ellipse's center. * \param xRadius The horizontal radius of the Ellipse in pixels. * \param yRadius The vertical radius of the Ellipse in pixels. - * \param color The color of the Ellipse's fill or outline - * \param filled Whether the Ellipse should be filled - * (set to true by default). + * \param yaw The Ellipse's yaw in 3D space. + * \param pitch The Ellipse's pitch in 3D space. + * \param roll The Ellipse's roll in 3D space. + * \param color The color of the Ellipse's fill. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color, bool filled) : ConvexPolygon((xRadius + yRadius) / 2, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), color); - } +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myXRadius = xRadius; + myYScale = myYRadius = yRadius; + myZScale = 1; + verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; + attribMutex.unlock(); + addVertex(0,0,0,color); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } } /*! - * \brief Explicitly constructs a new multicolored filled or outlined Ellipse. - * \details This function draws a Ellipse with the given center, radii, color, and outline color. + * \brief Explicitly constructs a new multicolored Ellipse. + * \details This function draws a Ellipse with the given center, radii, rotation, and color. * \param x The x coordinate of the Ellipse's center. * \param y The y coordinate of the Ellipse's center. + * \param z The z coordinate of the Ellipse's center. * \param xRadius The horizontal radius of the Ellipse in pixels. * \param yRadius The vertical radius of the Ellipse in pixels. - * \param color An array of colors for the Ellipse's fill or outline - * \param filled Whether the Ellipse should be filled - * (set to true by default). + * \param yaw The Ellipse's yaw in 3D space. + * \param pitch The Ellipse's pitch in 3D space. + * \param roll The Ellipse's roll in 3D space. + * \param color An array of colors for the Ellipse's fill. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color[], bool filled) : ConvexPolygon((xRadius + yRadius) / 2, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), color[i]); - } +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myXRadius = xRadius; + myYScale = myYRadius = yRadius; + myZScale = 1; + verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; + attribMutex.unlock(); + addVertex(0,0,0,color[0]); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } } -/*! - * \brief Explicitly constructs a new Ellipse with different monocolored fill and outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor The color of the Ellipse's fill - * \param outlineColor The color of the Ellipse's outline +/** + * \brief Mutates the horizontal radius of the Ellipse. + * \param xRadius The Ellipse's new x-radius. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor, outlineColor); - } +void Ellipse::setXRadius(GLfloat xRadius) { + if (xRadius <= 0) { + TsglDebug("Cannot have a Ellipse with x-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXRadius = xRadius; + myXScale = xRadius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with multicolored fill and monocolored outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor An array of colors for the Ellipse's fill - * \param outlineColor The color of the Ellipse's outline +/** + * \brief Mutates the horizontal radius of the Ellipse by the parameter amount. + * \param delta The amount by which to change the x-radius of the Ellipse. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor[i], outlineColor); - } +void Ellipse::changeXRadiusBy(GLfloat delta) { + if (myXRadius + delta <= 0) { + TsglDebug("Cannot have a Ellipse with x-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXRadius += delta; + myXScale += delta; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with monocolored fill and multicolored outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor The color of the Ellipse's fill - * \param outlineColor An array of colors for the Ellipse's outline +/** + * \brief Mutates the vertical radius of the Ellipse. + * \param YRadius The Ellipse's new y-radius. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor, outlineColor[i]); - } +void Ellipse::setYRadius(GLfloat yRadius) { + if (yRadius <= 0) { + TsglDebug("Cannot have a Ellipse with y-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myYRadius = yRadius; + myYScale = yRadius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with different multicolored fill and outline. - * \details This function draws a Ellipse with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor An array of colors for the Ellipse's fill - * \param outlineColor An array of colors for the Ellipse's outline +/** + * \brief Mutates the vertical radius of the Ellipse by the parameter amount. + * \param delta The amount by which to change the y-radius of the Ellipse. + */ +void Ellipse::changeYRadiusBy(GLfloat delta) { + if (myYRadius + delta <= 0) { + TsglDebug("Cannot have a Ellipse with y-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myYRadius += delta; + myYScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Sets the Ellipse to a new array of colors. + * \param c An array of the new ColorFloats. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor[i], outlineColor[i]); - } +void Ellipse::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0f; + vertices[3] = c[0].R; + vertices[4] = c[0].G; + vertices[5] = c[0].B; + vertices[6] = c[0].A; + myAlpha += c[0].A; + int colorIndex; + for (int i = 1; i < numberOfVertices; ++i) { + colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); + vertices[i*7 + 3] = c[colorIndex].R; + vertices[i*7 + 4] = c[colorIndex].G; + vertices[i*7 + 5] = c[colorIndex].B; + vertices[i*7 + 6] = c[colorIndex].A; + myAlpha += c[colorIndex].A; + } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } +/** + * \brief Accessor for Ellipse's colors. + * \details Populates the reference parameter vector with a ColorFloat for each section of Ellipse. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Ellipse will be pushed. + * \note Overrides Shape::getColors(). + */ +void Ellipse::getColors(std::vector &colorVec) { + attribMutex.lock(); + for (int i = 0; i < numberOfVertices; i+=verticesPerColor) { + colorVec.push_back(ColorFloat(vertices[i*7+3],vertices[i*7+4],vertices[i*7+5],vertices[i*7+6])); + } + attribMutex.unlock(); +} } \ No newline at end of file diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index 5612c9155..71f6e9970 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -15,21 +15,38 @@ namespace tsgl { */ class Ellipse : public ConvexPolygon { private: - + GLfloat myXRadius, myYRadius; + GLfloat verticesPerColor; public: - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color, bool filled = true); + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color); + + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color[], bool filled = true); + void setXRadius(GLfloat xRadius); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor); + void setYRadius(GLfloat yRadius); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor); + void changeXRadiusBy(GLfloat delta); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor[]); + void changeYRadiusBy(GLfloat delta); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + /*! + * \brief Accessor for the x-radius of the Ellipse. + * \details Returns the value of the myXRadius private variable, a GLfloat. + */ + GLfloat getXRadius() { return myXRadius; } + + /*! + * \brief Accessor for the y-radius of the Ellipse. + * \details Returns the value of the myYRadius private variable, a GLfloat. + */ + GLfloat getYRadius() { return myYRadius; } + void setColor(ColorFloat c) { Shape::setColor(c); } + + void setColor(ColorFloat c[]); + virtual void getColors(std::vector &colorVec); }; } diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp new file mode 100644 index 000000000..f036fa56e --- /dev/null +++ b/src/TSGL/Ellipsoid.cpp @@ -0,0 +1,312 @@ +#include "Ellipsoid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Ellipsoid. + * \details Explicit constructor for a Ellipsoid object. + * \param x The x coordinate of the center of the Ellipsoid. + * \param y The y coordinate of the center of the Ellipsoid. + * \param z The z coordinate of the center of the Ellipsoid. + * \param xRadius The Ellipsoid's radius on the x-axis. + * \param yRadius The Ellipsoid's radius on the y-axis. + * \param zRadius The Ellipsoid's radius on the z-axis. + * \param yaw The Ellipsoid's yaw. + * \param pitch The Ellipsoid's pitch. + * \param roll The Ellipsoid's roll. + * \param c A ColorFloat for the Ellipsoid's vertex colors. + * \warning An invariant is held where if any radius isn't positive then an error message is given. + * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. + */ +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { + if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + } + attribMutex.lock(); + myXRadius = xRadius; + myYRadius = yRadius; + myZRadius = zRadius; + myXScale = xRadius; + myYScale = yRadius; + myZScale = zRadius; + verticalSections = 36; + horizontalSections = 20; + geometryType = GL_TRIANGLE_STRIP; + numberOfVertices = verticalSections*horizontalSections*2 + 1; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = verticalSections*horizontalSections*4 + 1; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + isOutlined = false; + attribMutex.unlock(); + for(float b=0;b &colorVec) { + attribMutex.lock(); + for(int b=0;b &colorVec); +}; + +} + +#endif /* ELLIPSOID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index 08ce1ad55..d4d68c32c 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -5,144 +5,165 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Image. * \details This is the explicit constructor for the Image class. - * \param filename The filename of the image to load. - * \param loader A reference pointer to the TextureHandler with which to load the image. - * \param x The x coordinate of the left of the Image. - * \param y The y coordinate of the top of the Image. + * \param x The x coordinate of the center of the Image. + * \param y The y coordinate of the center of the Image. + * \param z The z coordinate of the center of the Image. + * \param filename The filename of the image to load, a std::string * \param width The width of the Image. * \param height The height of the Image. - * \param alhpa The alpha of the Image. + * \param yaw The yaw orientation of the Image. + * \param pitch The pitch orientation of the Image. + * \param roll The roll orientation of the Image. + * \param alpha The alpha of the Image. * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. */ -Image::Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha) { - isTextured = true; // Let the Canvas know we're a textured object - myTexture = 0; // Fix no texture initialization warning - myWidth = width; myHeight = height; - if (myWidth <= 0 || myHeight <= 0) { - TextureHandler::getDimensions(filename,myWidth,myHeight); - } - myCenterX = x + myWidth / 2; - myCenterY = y + myHeight / 2; - setRotationPoint(myCenterX, myCenterY); - currentRotation = 0; - myFile = filename; - myLoader = &loader; - vertices = new float[32]; - vertices[0] = x; - vertices[1] = y; - vertices[8] = x + myWidth; - vertices[9] = y; - vertices[16] = x; - vertices[17] = y + myHeight; - vertices[24] = x + myWidth; - vertices[25] = y + myHeight; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; - vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = alpha; - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left - vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right +Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll, float alpha) : Drawable(x,y,z,yaw,pitch,roll) { + if (width <= 0 || height <= 0) { + TsglDebug("Cannot have an Image with width or height less than or equal to 0."); + return; + } + if (alpha < 0.0 || alpha > 1.0) { + TsglDebug("Cannot have an Image with alpha not between 0.0 and 1.0."); + return; + } + attribMutex.lock(); + shaderType = TEXTURE_SHADER_TYPE; + myWidth = width; myHeight = height; + myXScale = width; myYScale = height; + myFile = filename; + myAlpha = alpha; + + // Load the image. + stbi_set_flip_vertically_on_load(true); + data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); + tsglAssert(data, "stbi_load(filename) failed."); + // vertex allocation and assignment + vertices = new GLfloat[30]; + + // positions (x,y,z) texture coords + // 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right + // 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right + //-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left + // second triangle + // 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right + //-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left + //-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left + vertices[0] = vertices[1] = vertices[5] = vertices[15] = vertices[16] = vertices[26] = 0.5; // x + y + vertices[6] = vertices[10] = vertices[11] = vertices[20] = vertices[21] = vertices[25] = -0.5; // x + y + vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = 0; // z + vertices[3] = vertices[4] = vertices[8] = vertices[18] = vertices[19] = vertices[29] = 1.0; // texture coord x + y + vertices[9] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[28] = 0.0; // texture coord x + y + init = true; + attribMutex.unlock(); } /*! * \brief Draw the Image. * \details This function actually draws the Image to the Canvas. */ -void Image::draw() { - unsigned int w, h; - myLoader->loadPicture(myFile, w, h, myTexture); - - glBindTexture(GL_TEXTURE_2D, myTexture); - 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_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +void Image::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + unsigned int alphaLoc = glGetUniformLocation(shader->ID, "alpha"); + glUniform1f(alphaLoc, myAlpha); + + glGenTextures(1, &myTexture); + // enable textures and bind the texture id + glBindTexture(GL_TEXTURE_2D, myTexture); + + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelWidth, pixelHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDeleteTextures(1, &myTexture); } -/*! - * \brief Mutator for the center coordinates of the Image. - * \details Alters the values of the myCenterX and myCenterY private variables. - * \param x Float value for the new center x-coordinate. - * \param y Float value for the new center y-coordinate. - * \warning This will also alter the Image's rotation point if and only if the - * old rotation point was at the Image's old center. +/** + * \brief Mutates the distance from the left side of the Image base to its right side. + * \param width The Image's new width. */ -void Image::setCenter(float x, float y) { - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - setRotationPoint(x, y); - } - if(myCenterX != x || myCenterY != y) { - float deltaX = x - myCenterX; - float deltaY = y - myCenterY; - for(int i = 0; i < 4; i++) { - vertices[8*i] += deltaX; - vertices[8*i+1] += deltaY; +void Image::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have an Image with width less than or equal to 0."); + return; } - myCenterX = x; - myCenterY = y; - } - attribMutex.unlock(); + attribMutex.lock(); + myWidth = width; + myXScale = width; + attribMutex.unlock(); } -/*! - * \brief Mutator for the coordinates of the Image. - * \details Alters all coordinate variables for the Image. - * \param deltaX Float value of how much to alter the y-coordinates. - * \param deltaY Float value of how much to alter the y-coordinates. - * \warning This will also alter the Image's rotation point if and only if the - * old rotation point was at the Image's old center. +/** + * \brief Mutates the distance from the left side of the Image base to its right side by the parameter amount. + * \param delta The amount by which to change the width of the Image. */ -void Image::moveImageBy(float deltaX, float deltaY) { - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - if(deltaX != 0 || deltaY != 0) { - for(int i = 0; i < 4; i++) { - vertices[8*i] += deltaX; - vertices[8*i+1] += deltaY; +void Image::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have an Image with width less than or equal to 0."); + return; } - myCenterX += deltaX; - myCenterY += deltaY; - } - attribMutex.unlock(); + attribMutex.lock(); + myWidth += delta; + myXScale += delta; + attribMutex.unlock(); } -/*! - * \brief Mutator for the rotation of the Image. - * \details Rotates the Image corners around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Image. +/** + * \brief Mutates the distance from the top side of the Image base to its bottom side. + * \param height The Image's new height. */ -void Image::setRotation(float radians) { - if(radians != currentRotation) { +void Image::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have an Image with height less than or equal to 0."); + return; + } attribMutex.lock(); - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; - for(int i = 0; i < 4; i++) { - float x = vertices[8*i]; - float y = vertices[8*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - vertices[8*i] = x; - vertices[8*i+1] = y; + myWidth = height; + myYScale = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the top side of the Image base to its bottom side by the parameter amount. + * \param delta The amount by which to change the height of the Image. + */ +void Image::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have an Image with height less than or equal to 0."); + return; } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; attribMutex.unlock(); - } } /*! @@ -152,22 +173,50 @@ void Image::setRotation(float radians) { * \param width New width of the Image. * \param height New height of the Image. */ -void Image::changeFileName(std::string filename, int width, int height) { - attribMutex.lock(); - myFile = filename; - myWidth = width; myHeight = height; - if (myWidth <= 0 || myHeight <= 0) { - TextureHandler::getDimensions(filename,myWidth,myHeight); - } - vertices[0] = myCenterX - myWidth/2; - vertices[1] = myCenterY - myHeight/2; - vertices[8] = myCenterX + myWidth/2; - vertices[9] = myCenterY - myHeight/2; - vertices[16] = myCenterX - myWidth/2; - vertices[17] = myCenterY + myHeight/2; - vertices[24] = myCenterX + myWidth/2; - vertices[25] = myCenterY + myHeight/2; - attribMutex.unlock(); +void Image::changeFile(std::string filename) { + attribMutex.lock(); + init = false; + stbi_image_free(data); + // Load the image. + stbi_set_flip_vertically_on_load(true); + data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); + tsglAssert(data, "stbi_load(filename) failed."); + init = true; + attribMutex.unlock(); +} + +/** + * \brief Alters the Image's transparency + * \param delta The Image's new alpha value. + * \note If parameter not 0.0 <= alpha <= 1.0 then this method will have no effect. + */ +void Image::setAlpha(float alpha) { + if (alpha < 0.0 || alpha > 1.0) { + TsglDebug("Cannot have an Image with alpha not 0.0 <= alpha <= 1.0."); + return; + } + attribMutex.lock(); + myAlpha = alpha; + attribMutex.unlock(); } +/*! + * \brief Gets the dimensions of an image + * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. + * \param filename The file name of the picture. + * \param width A reference variable for holding the width of the picture. + * \param height A reference variable for holding the height of the picture. + */ +void Image::getFileResolution(std::string filename, int &width, int &height) { + int w = 0, h = 0; + stbi_info(filename.c_str(), &w, &h, 0); + width = w; height = h; +} + +Image::~Image() { + glDeleteTextures(1, &myTexture); + stbi_image_free(data); +} + + } diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index e00841db0..caaff14c9 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -1,5 +1,5 @@ /* - * Image.h extends Shape and provides a class for drawing an image to a Canvas. + * Image.h extends Drawable and provides a class for drawing an image to a Canvas. */ #ifndef IMAGE_H_ @@ -7,8 +7,8 @@ #include -#include "Drawable.h" // For extending our Shape object -#include "TextureHandler.h" // For loading images +#include "Drawable.h" // For extending our Drawable object +#include #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -20,46 +20,51 @@ namespace tsgl { * \note For the time being, there is no way to measure the size of an image once it's loaded. * Therefore, the width and height must be specified manually, and stretching may occur if the * input dimensions don't match the images actual dimensions. - * \note Additionally, an ImageLoader must be passed as an argument. This ImageLoader is automatically - * constructed with the Canvas as the private *loader* variable. At the moment, there is no way to - * extend Canvas::drawImage() function due to this privatization. * \warning Aside from an error message output to stderr, Image gives no indication if an image failed to load. */ class Image : public Drawable { private: - int myWidth, myHeight; - float currentRotation; - float *vertices; + unsigned char * data = 0; + GLfloat myWidth, myHeight; + GLint pixelWidth, pixelHeight; std::string myFile; - GLtexture myTexture; - TextureHandler* myLoader; + GLuint myTexture; public: - Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha = 1.0f); + Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll, float alpha = 1.0f); - virtual void draw(); + virtual void draw(Shader * shader); /*! * \brief Accessor for the image's height. * \return The height of the Image. */ - int getHeight() { return myHeight; } + GLfloat getHeight() { return myHeight; } /*! * \brief Accessor for the image's width. * \return The width of the Image. */ - int getWidth() { return myWidth; } + GLfloat getWidth() { return myWidth; } - void setCenter(float x, float y); + void setWidth(GLfloat width); - void moveImageBy(float deltaX, float deltaY); + void setHeight(GLfloat height); - virtual void setRotation(float radians); + void changeWidthBy(GLfloat delta); - void changeFileName(std::string filename, int width = 0, int height = 0); + void changeHeightBy(GLfloat delta); - ~Image() { delete[] vertices; } + void changeFile(std::string filename); + void setAlpha(float newAlpha); + + GLint getPixelHeight() { return pixelHeight; } + + GLint getPixelWidth() { return pixelWidth; } + + static void getFileResolution(std::string filename, int &width, int &height); + + ~Image(); }; } diff --git a/src/TSGL/IntegralViewer.cpp b/src/TSGL/IntegralViewer.cpp index c9a324111..caaa07245 100644 --- a/src/TSGL/IntegralViewer.cpp +++ b/src/TSGL/IntegralViewer.cpp @@ -17,16 +17,16 @@ namespace tsgl { * \return A new IntegralViewer with the specified dimensions, bounds, and function description. */ IntegralViewer::IntegralViewer(functionPointer f, int width, int height, Decimal startX, Decimal stopX, Decimal startY, Decimal stopY, std::string fname) { - myF = f; - myWidth = width; myHeight = height; - myStartX = startX; myStopX = stopX; - myStartY = startY; myStopY = stopY; - myRecTime = myTrapTime = 0; - myDelay = FRAME; - std::stringstream ss; - ss.str("Integral of " + fname + " from " + to_string(myStartX) + " to " + to_string(myStopX)); - setupCanvas(myTrapCanvas, ss.str() + " using Trapezoids", myDelay); //Canvas for trapezoid method - setupCanvas(myRecCanvas, ss.str() + " using Rectangles", myDelay); //Canvas for rectangle method + myF = f; + myWidth = width; myHeight = height; + myStartX = startX; myStopX = stopX; + myStartY = startY; myStopY = stopY; + myRecTime = myTrapTime = 0; + myDelay = FRAME; + std::stringstream ss; + ss.str("Integral of " + fname + " from " + to_string(myStartX) + " to " + to_string(myStopX)); + setupCanvas(myTrapCanvas, ss.str() + " using Trapezoids", myDelay); //Canvas for trapezoid method + setupCanvas(myRecCanvas, ss.str() + " using Rectangles", myDelay); //Canvas for rectangle method } /*! @@ -35,45 +35,52 @@ IntegralViewer::IntegralViewer(functionPointer f, int width, int height, Decimal * \details Frees up memory that was allocated to a IntegralViewer instance. */ IntegralViewer::~IntegralViewer() { - if (myRecCanvas->isOpen()) - myRecCanvas->stop(); - if (myTrapCanvas->isOpen()) - myTrapCanvas->stop(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - delete myRecCanvas; - delete myTrapCanvas; + if (myRecCanvas->isOpen()) + myRecCanvas->stop(); + if (myTrapCanvas->isOpen()) + myTrapCanvas->stop(); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + delete myRecCanvas; + delete myTrapCanvas; } void IntegralViewer::drawLabels(CartesianCanvas*& can) { - const int FSIZE = 32; - const float /* cpw = can->getPixelWidth(), */ cph = can->getPixelHeight(); - const float /* xoff = cpw*FSIZE, */ yoff = cph*FSIZE; - - bool blorigin = (myStartX == 0 && myStartY == 0); - bool tlorigin = (myStartX == 0 && myStopY == 0); - - can->drawText(to_string(myStartX), myStartX, myStartY-yoff, FSIZE); - can->drawText(to_string(myStopX), myStopX, myStartY-yoff, FSIZE); - if (!blorigin) - can->drawText(to_string(myStartY), 0, myStartY-1.5f*yoff, FSIZE); - if (!tlorigin) - can->drawText(to_string(myStopY), 0, myStopY, FSIZE); + CartesianBackground * bg = can->getBackground(); + const float /* cpw = can->getPixelWidth(), */ cph = can->getPixelHeight(); + const float FSIZE = cph * 30; + const float /* xoff = cpw*FSIZE, */ yoff = cph * 20; + + bool blorigin = (myStartX == 0 && myStartY == 0); + bool tlorigin = (myStopX == 0 && myStopY == 0); + + std::string startXString = to_string(myStartX); + std::string startYString = to_string(myStartY); + std::string stopXString = to_string(myStopX); + std::string stopYString = to_string(myStopY); + + bg->drawText(cph * 10 + myStartX + cph * 2 * startXString.size(), myStartY-yoff, 0, startXString, "./assets/freefont/FreeSerif.ttf", FSIZE, 0,0,0, BLACK); + bg->drawText(-cph * 10 + myStopX + cph * 2 * stopXString.size(), myStartY-yoff, 0, stopXString, "./assets/freefont/FreeSerif.ttf", FSIZE, 0,0,0, BLACK); + if (!blorigin) + bg->drawText(cph * 10 + cph * 2 * startYString.size(), myStartY-yoff, 0, startYString, "./assets/freefont/FreeSerif.ttf", FSIZE, 0,0,0, BLACK); + if (!tlorigin) + bg->drawText(cph * 10 + cph * 2 * stopYString.size(), myStopY+yoff, 0, stopYString, "./assets/freefont/FreeSerif.ttf", FSIZE, 0,0,0, BLACK); } void IntegralViewer::setupCanvas(CartesianCanvas*& can, const std::string& label, double delay) { - const float BORDER = (myStopX-myStartX)/10.0f; - const float SPACING = BORDER; - can = new CartesianCanvas(-1, -1, myWidth, myHeight, myStartX - BORDER, myStartY - BORDER, - myStopX + BORDER, myStopY + BORDER, label, delay); + const float BORDER = (myStopX-myStartX)/10.0f; + const float SPACING = BORDER; + can = new CartesianCanvas(-1, -1, myWidth, myHeight, myStartX - BORDER, myStartY - BORDER, + myStopX + BORDER, myStopY + BORDER, label, GRAY, delay); - can->setBackgroundColor(ColorFloat(0.95f, 0.95f, 0.95f, 1.0f)); + // can->setBackgroundColor(ColorFloat(0.95f, 0.95f, 0.95f, 1.0f)); + CartesianBackground * bg = can->getBackground(); - can->start(); + can->start(); - can->drawRectangle(myStartX,myStartY,myStopX - myStartX, myStartY - myStopY,WHITE); //Area we're drawing to - can->drawPartialFunction(myF,myStartX,myStopX,0,ColorInt(0,0,255)); //Outline of function - can->drawAxes(0, 0, SPACING, SPACING); //Axes marks - drawLabels(can); + bg->drawRectangle((myStartX + myStopX)/2,(myStartY+myStopY)/2,0, myStopX - myStartX, myStopY - myStartY, 0,0,0,WHITE); //Area we're drawing to + bg->drawPartialFunction(myF,myStartX,myStopX,ColorInt(0,0,255)); //Outline of function + bg->drawAxes(0, 0, SPACING, SPACING); //Axes marks + drawLabels(can); } /*! @@ -83,31 +90,32 @@ void IntegralViewer::setupCanvas(CartesianCanvas*& can, const std::string& label * the rectangle method. */ long double IntegralViewer::rectangleEvaluate(long long numRectangles) { - double startTime = omp_get_wtime(); - long double result = 0.0, - recWidth = fabs(myStopX - myStartX) / numRectangles, - halfRecWidth = recWidth / 2.0; - #pragma omp parallel reduction(+:result) - { - Decimal xLo = 0.0, xMid = 0.0, y = 0.0; - ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); - tcol.A = 0.7f; - - #pragma omp for - for (long long i = 0; i < numRectangles; ++i) { - if (!myRecCanvas->isOpen()) continue; - myRecCanvas->sleep(); - xLo = myStartX + i * recWidth; - xMid = xLo + halfRecWidth; - y = (*myF)(xMid); - result += y; - myRecCanvas->drawRectangle(xLo, y, recWidth, y, tcol); + CartesianBackground * bg = myRecCanvas->getBackground(); + double startTime = omp_get_wtime(); + long double result = 0.0, + recWidth = fabs(myStopX - myStartX) / numRectangles, + halfRecWidth = recWidth / 2.0; + #pragma omp parallel reduction(+:result) + { + Decimal xLo = 0.0, xMid = 0.0, y = 0.0; + ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); + tcol.A = 0.7f; + + #pragma omp for + for (long long i = 0; i < numRectangles; ++i) { + if (!myRecCanvas->isOpen()) continue; + myRecCanvas->sleep(); + xLo = myStartX + i * recWidth; + xMid = xLo + halfRecWidth; + y = (*myF)(xMid); + result += y; + bg->drawRectangle(xMid, y/2,0, recWidth, abs(y), 0,0,0, tcol); + } + result *= recWidth; } - result *= recWidth; - } - myRecTime = omp_get_wtime() - startTime; - myRecCanvas->wait(); - return result; + myRecTime = omp_get_wtime() - startTime; + myRecCanvas->wait(); + return result; } /*! @@ -117,38 +125,41 @@ long double IntegralViewer::rectangleEvaluate(long long numRectangles) { * the trapezoid method. */ long double IntegralViewer::trapezoidEvaluate(long long numTrapezoids) { - double startTime = omp_get_wtime(); - long double result = 0.0, - trapWidth = fabs(myStopX - myStartX) / numTrapezoids, - halfTrapWidth = trapWidth / 2.0; - #pragma omp parallel reduction(+:result) - { - Decimal leftX = 0.0, rightX = 0.0, leftY = 0.0, rightY = 0.0; - Decimal xValues[4] = {0.0}, yValues[4] = {0.0}; - ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); - tcol.A = 0.7; - ColorFloat colorValues[4] = {tcol, tcol, tcol, tcol}; - - #pragma omp for - for (long long i = 0; i < numTrapezoids; ++i) { - if (!myTrapCanvas->isOpen()) continue; - leftX = myStartX + i * trapWidth; - rightX = leftX + trapWidth; - leftY = (*myF)(leftX); - rightY = (*myF)(rightX); - result += ((leftY + rightY) * halfTrapWidth); - - xValues[0] = xValues[1] = leftX; - xValues[2] = xValues[3] = rightX; - yValues[1] = leftY; yValues[2] = rightY; - - myTrapCanvas->drawConvexPolygon(4, xValues, yValues, colorValues); - myTrapCanvas->sleep(); + CartesianBackground * cart = myTrapCanvas->getBackground(); + double startTime = omp_get_wtime(); + long double result = 0.0, + trapWidth = fabs(myStopX - myStartX) / numTrapezoids, + halfTrapWidth = trapWidth / 2.0; + #pragma omp parallel reduction(+:result) + { + Decimal leftX = 0.0, rightX = 0.0, leftY = 0.0, rightY = 0.0; + float xValues[4] = {0.0}, yValues[4] = {0.0}; + Decimal centerX, centerY; + ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); + tcol.A = 0.7; + + #pragma omp for + for (long long i = 0; i < numTrapezoids; ++i) { + if (!myTrapCanvas->isOpen()) continue; + leftX = myStartX + i * trapWidth; + rightX = leftX + trapWidth; + leftY = (*myF)(leftX); + rightY = (*myF)(rightX); + result += ((leftY + rightY) * halfTrapWidth); + + xValues[0] = xValues[1] = leftX; + xValues[2] = xValues[3] = rightX; + yValues[1] = leftY; yValues[2] = rightY; + centerX = (leftX + rightX) / 2; + centerY = (leftY + rightY) / 2; + + cart->drawConvexPolygon(centerX, centerY, 0, 4, xValues, yValues, 0,0,0, tcol); + myTrapCanvas->sleep(); + } } - } - myTrapTime = omp_get_wtime() - startTime; - myTrapCanvas->wait(); - return result; + myTrapTime = omp_get_wtime() - startTime; + myTrapCanvas->wait(); + return result; } } diff --git a/src/TSGL/Keynums.h b/src/TSGL/Keynums.h index a0e2a0cfb..e8701f1d8 100644 --- a/src/TSGL/Keynums.h +++ b/src/TSGL/Keynums.h @@ -147,12 +147,13 @@ enum Key { }; /*! \brief Enum for keyboard key / mouse button states. - * \details Action is an enum for whether a keyboard / mouse button is pressed or released. - * \note These are directly mapped to GLFW's integer definitions GLFW_PRESS and GLFW_RELEASE. + * \details Action is an enum for whether a keyboard / mouse button is pressed, released, or held until it repeats. + * \note These are directly mapped to GLFW's integer definitions GLFW_PRESS, GLFW_RELEASE, and GLFW_REPEAT. */ enum Action { TSGL_PRESS = GLFW_PRESS, - TSGL_RELEASE = GLFW_RELEASE + TSGL_RELEASE = GLFW_RELEASE, + TSGL_REPEAT = GLFW_REPEAT }; } diff --git a/src/TSGL/Line.cpp b/src/TSGL/Line.cpp index ddb1223c3..3dacaf8a6 100644 --- a/src/TSGL/Line.cpp +++ b/src/TSGL/Line.cpp @@ -5,68 +5,406 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Line. * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. + * \param x The x coordinate of the center of the line. + * \param y The y coordinate of the center of the line. + * \param z The z coordinate of the center of the line. + * \param length The length of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. * \param color The reference variable to the color of the Line. - * \return A new Line with the specified endpoints and color. + * \return A new Line with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the line will be drawn directly parallel to the x-axis. */ -Line::Line(int x1, int y1, int x2, int y2, const ColorFloat color) : Polyline(2) { - addVertex(x1, y1, color); - addVertex(x2, y2, color); +Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color) : Polyline(x,y,z,2,yaw,pitch,roll) { + if (length <= 0) + TsglDebug("Cannot have a line with length less than or equal to 0."); + attribMutex.lock(); + myLength = length; + myEndpointX1 = -length/2 + x; + myEndpointY1 = y; + myEndpointZ1 = z; + myEndpointX2 = -length/2 + x; + myEndpointY2 = y; + myEndpointZ2 = z; + attribMutex.unlock(); + addVertex(-length/2, 0, 0, color); + addVertex(length/2, 0, 0, color); } /*! * \brief Explicitly constructs a new Line. * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array for the colors of the line endpoints. - * \return A new Line with the specified endpoints and colors. + * \param x The x coordinate of the center of the line. + * \param y The y coordinate of the center of the line. + * \param z The z coordinate of the center of the line. + * \param length The length of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the colors of the Line. + * \return A new Line with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the line will be drawn directly parallel to the x-axis. */ -Line::Line(int x1, int y1, int x2, int y2, const ColorFloat color[]) : Polyline(2) { - addVertex(x1, y1, color[0]); - addVertex(x2, y2, color[1]); +Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color[]) : Polyline(x,y,z,2,yaw,pitch,roll) { + if (length <= 0) + TsglDebug("Cannot have a line with length less than or equal to 0."); + attribMutex.lock(); + myLength = length; + myEndpointX1 = -length/2 + x; + myEndpointY1 = y; + myEndpointZ1 = z; + myEndpointX2 = -length/2 + x; + myEndpointY2 = y; + myEndpointZ2 = z; + attribMutex.unlock(); + addVertex(-length/2, 0, 0, color[0]); + addVertex(length/2, 0, 0, color[1]); +} + +/*! + * \brief Explicitly constructs a new Line. + * \details This is the constructor for the Line class. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the color of the Line. + * \return A new Line with the specified length and color. + */ +Line::Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color) : Polyline((x2 + x1) / 2, (y2 + y1) / 2, (z2 + z1) / 2, 2, yaw, pitch, roll) { + attribMutex.lock(); + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + myEndpointX1 = x1; + myEndpointY1 = y1; + myEndpointZ1 = z1; + myEndpointX2 = x2; + myEndpointY2 = y2; + myEndpointZ2 = z2; + attribMutex.unlock(); + addVertex(x1 - myCenterX, y1 - myCenterY, z1 - myCenterZ, color); + addVertex(x2 - myCenterX, y2 - myCenterY, z2 - myCenterZ, color); +} + +/*! + * \brief Explicitly constructs a new Line. + * \details This is the constructor for the Line class. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the colors of the Line. + * \return A new Line with the specified length and color. + */ +Line::Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color[]) : Polyline((x2 + x1) / 2, (y2 + y1) / 2, (z2 + z1) / 2, 2, yaw, pitch, roll) { + attribMutex.lock(); + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + myEndpointX1 = x1; + myEndpointY1 = y1; + myEndpointZ1 = z1; + myEndpointX2 = x2; + myEndpointY2 = y2; + myEndpointZ2 = z2; + attribMutex.unlock(); + addVertex(x1 - myCenterX, y1 - myCenterY, z1 - myCenterZ, color[0]); + addVertex(x2 - myCenterX, y2 - myCenterY, z2 - myCenterZ, color[1]); +} + +/** + * \brief Moves the line's first endpoint to the parameter coordinates. + * \param x The Line's first endpoint's new x-coordinate. + * \param y The Line's first endpoint's new y-coordinate. + * \param z The Line's first endpoint's new z-coordinate. + * \warning Upon altering an endpoint, center coordinates will be altered accordingly, + * yaw, pitch, and roll will be reset to 0, + * and rotation point coordinates will be adjusted if they previously matched the center of the line. + */ +void Line::setFirstEndpoint(float x, float y, float z) { + attribMutex.lock(); + myEndpointX1 = x; myEndpointY1 = y; myEndpointZ1 = z; + myLength = sqrt(pow(myEndpointX2 - myEndpointX1, 2) + pow(myEndpointY2 - myEndpointY1, 2) + pow(myEndpointZ2 - myEndpointZ1, 2)); + if (centerMatchesRotationPoint()) { + myRotationPointX = (myEndpointX2 + myEndpointX1) / 2; + myRotationPointY = (myEndpointY2 + myEndpointY1) / 2; + myRotationPointZ = (myEndpointZ2 + myEndpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (myEndpointX2 + myEndpointX1) / 2; + myCenterY = (myEndpointY2 + myEndpointY1) / 2; + myCenterZ = (myEndpointZ2 + myEndpointZ1) / 2; + } + myCurrentYaw = 0; + myCurrentPitch = 0; + myCurrentRoll = 0; + vertices[0] = myEndpointX1 - myCenterX; + vertices[1] = myEndpointY1 - myCenterY; + vertices[2] = myEndpointZ1 - myCenterZ; + vertices[7] = myEndpointX2 - myCenterX; + vertices[8] = myEndpointY2 - myCenterY; + vertices[9] = myEndpointZ2 - myCenterZ; + attribMutex.unlock(); +} + +/** + * \brief Moves the line's second endpoint to the parameter coordinates. + * \param x The Line's second endpoint's new x-coordinate. + * \param y The Line's second endpoint's new y-coordinate. + * \param z The Line's second endpoint's new z-coordinate. + * \warning Upon altering an endpoint, center coordinates will be altered accordingly, + * yaw, pitch, and roll will be reset to 0, + * and rotation point coordinates will be adjusted if they previously matched the center of the line. + */ +void Line::setSecondEndpoint(float x, float y, float z) { + attribMutex.lock(); + myEndpointX2 = x; myEndpointY2 = y; myEndpointZ2 = z; + myLength = sqrt(pow(myEndpointX2 - myEndpointX1, 2) + pow(myEndpointY2 - myEndpointY1, 2) + pow(myEndpointZ2 - myEndpointZ1, 2)); + if (centerMatchesRotationPoint()) { + myRotationPointX = (myEndpointX2 + myEndpointX1) / 2; + myRotationPointY = (myEndpointY2 + myEndpointY1) / 2; + myRotationPointZ = (myEndpointZ2 + myEndpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (myEndpointX2 + myEndpointX1) / 2; + myCenterY = (myEndpointY2 + myEndpointY1) / 2; + myCenterZ = (myEndpointZ2 + myEndpointZ1) / 2; + } + myCurrentYaw = 0; + myCurrentPitch = 0; + myCurrentRoll = 0; + vertices[0] = myEndpointX1 - myCenterX; + vertices[1] = myEndpointY1 - myCenterY; + vertices[2] = myEndpointZ1 - myCenterZ; + vertices[7] = myEndpointX2 - myCenterX; + vertices[8] = myEndpointY2 - myCenterY; + vertices[9] = myEndpointZ2 - myCenterZ; + attribMutex.unlock(); } /** - * \brief Moves one end of the Line. - * \details Moves the end of the line originally specified by (x1, y1). - * \param x The new x coordinate. - * \param y The new y coordinate. + * \brief Mutates the line's length to the new parameter value. + * \param length The Line's new length. */ -void Line::setFirstEnd(float x, float y) { - attribMutex.lock(); - vertices[0] = x; - vertices[1] = y; - attribMutex.unlock(); +void Line::setLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have a Line with length less than or equal to 0."); + return; + } + attribMutex.lock(); + float ratio = length / myLength; + myLength = length; + vertices[0] *= ratio; + vertices[1] *= ratio; + vertices[2] *= ratio; + vertices[7] *= ratio; + vertices[8] *= ratio; + vertices[9] *= ratio; + attribMutex.unlock(); } /** - * \brief Moves one end of the Line. - * \details Moves the end of the line originally specified by (x2, y2). - * \param x The new x coordinate. - * \param y The new y coordinate. + * \brief Mutates the line's length by the parameter value. + * \param delta The difference between the new and old line lengths. */ -void Line::setSecondEnd(float x, float y) { - attribMutex.lock(); - vertices[6] = x; - vertices[7] = y; - attribMutex.unlock(); +void Line::changeLengthBy(GLfloat delta) { + if (myLength + delta <= 0) { + TsglDebug("Cannot have a Line with length less than or equal to 0."); + printf("failure\n"); + return; + } + attribMutex.lock(); + float ratio = (myLength + delta) / myLength; + myLength += delta; + vertices[0] *= ratio; + vertices[1] *= ratio; + vertices[2] *= ratio; + vertices[7] *= ratio; + vertices[8] *= ratio; + vertices[9] *= ratio; + attribMutex.unlock(); } /** - * \brief Calculates the length of the line. - * \details Finds the distance between the two ends of the line. - * \return Length of the Line. + * \brief Returns the x-coordinate of the line's first endpoint. + * \details Returns the value of the endpointX1 instance variable. + * \return x-coordinate of the Line's first endpoint. */ -float Line::getLength() { - attribMutex.lock(); - float length = sqrt((vertices[0]-vertices[2])*(vertices[0]-vertices[2])+(vertices[1]-vertices[3])*(vertices[1]-vertices[3])); - attribMutex.unlock(); - return length; +GLfloat Line::getFirstEndpointX() { + attribMutex.lock(); + float ex1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ex1 = myEndpointX1; + attribMutex.unlock(); + return ex1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ex1 = myEndpointX1; + attribMutex.unlock(); + return ex1; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ex1 = cosYaw * cosPitch * (myEndpointX1 - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myEndpointY1 - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myEndpointZ1 - myRotationPointZ) + myRotationPointX; + attribMutex.unlock(); + return ex1; } + +/** + * \brief Returns the y-coordinate of the line's first endpoint. + * \details Returns the value of the endpointY1 instance variable. + * \return y-coordinate of the Line's first endpoint. + */ +GLfloat Line::getFirstEndpointY() { + attribMutex.lock(); + float ey1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ey1 = myEndpointY1; + attribMutex.unlock(); + return ey1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ey1 = myEndpointY1; + attribMutex.unlock(); + return ey1; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ey1 = sinYaw * cosPitch * (myEndpointX1 - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myEndpointY1 - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myEndpointZ1 - myRotationPointZ) + myRotationPointY; + attribMutex.unlock(); + return ey1; +} + +/** + * \brief Returns the z-coordinate of the line's first endpoint. + * \details Returns the value of the endpointZ1 instance variable. + * \return z-coordinate of the Line's first endpoint. + */ +GLfloat Line::getFirstEndpointZ() { + attribMutex.lock(); + float ez1; + if (myEndpointX1 == myRotationPointX && myEndpointY1 == myRotationPointY && myEndpointZ1 == myRotationPointZ) { + ez1 = myEndpointZ1; + attribMutex.unlock(); + return ez1; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ez1 = myEndpointZ1; + attribMutex.unlock(); + return ez1; + } + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ez1 = -sinPitch * (myEndpointX1 - myRotationPointX) + cosPitch * sinRoll * (myEndpointY1 - myRotationPointY) + cosPitch * cosRoll * (myEndpointZ1 - myRotationPointZ) + myRotationPointZ; + attribMutex.unlock(); + return ez1; +} + +/** + * \brief Returns the x-coordinate of the line's second endpoint. + * \details Returns the value of the endpointX2 instance variable. + * \return x-coordinate of the Line's second endpoint. + */ +GLfloat Line::getSecondEndpointX() { + attribMutex.lock(); + float ex2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ex2 = myEndpointX2; + attribMutex.unlock(); + return ex2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ex2 = myEndpointX2; + attribMutex.unlock(); + return ex2; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ex2 = cosYaw * cosPitch * (myEndpointX2 - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myEndpointY2 - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myEndpointZ2 - myRotationPointZ) + myRotationPointX; + attribMutex.unlock(); + return ex2; +} + +/** + * \brief Returns the y-coordinate of the line's second endpoint. + * \details Returns the value of the endpointY2 instance variable. + * \return y-coordinate of the Line's second endpoint. + */ +GLfloat Line::getSecondEndpointY() { + attribMutex.lock(); + float ey2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ey2 = myEndpointY2; + attribMutex.unlock(); + return ey2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ey2 = myEndpointY2; + attribMutex.unlock(); + return ey2; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ey2 = sinYaw * cosPitch * (myEndpointX2 - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myEndpointY2 - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myEndpointZ2 - myRotationPointZ) + myRotationPointY; + attribMutex.unlock(); + return ey2; +} + +/** + * \brief Returns the z-coordinate of the line's second endpoint. + * \details Returns the value of the endpointZ2 instance variable. + * \return z-coordinate of the Line's second endpoint. + */ +GLfloat Line::getSecondEndpointZ() { + attribMutex.lock(); + float ez2; + if (myEndpointX2 == myRotationPointX && myEndpointY2 == myRotationPointY && myEndpointZ2 == myRotationPointZ) { + ez2 = myEndpointZ2; + attribMutex.unlock(); + return ez2; + } + if (myCurrentYaw == 0 && myCurrentPitch == 0 && myCurrentRoll == 0) { + ez2 = myEndpointZ2; + attribMutex.unlock(); + return ez2; + } + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + ez2 = -sinPitch * (myEndpointX2 - myRotationPointX) + cosPitch * sinRoll * (myEndpointY2 - myRotationPointY) + cosPitch * cosRoll * (myEndpointZ2 - myRotationPointZ) + myRotationPointZ; + attribMutex.unlock(); + return ez2; +} + } diff --git a/src/TSGL/Line.h b/src/TSGL/Line.h index 283c6e2d5..690e98b22 100755 --- a/src/TSGL/Line.h +++ b/src/TSGL/Line.h @@ -15,17 +15,43 @@ namespace tsgl { */ class Line : public Polyline { private: - + GLfloat myLength; + GLfloat myEndpointX1, myEndpointY1, myEndpointZ1, myEndpointX2, myEndpointY2, myEndpointZ2; public: - Line(int x1, int y1, int x2, int y2, const ColorFloat color); + Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color); - Line(int x1, int y1, int x2, int y2, const ColorFloat color[]); + Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color[]); - void setFirstEnd(float x, float y); + Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color); - void setSecondEnd(float x, float y); + Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color[]); - float getLength(); + void setFirstEndpoint(float x, float y, float z); + + void setSecondEndpoint(float x, float y, float z); + + void setLength(GLfloat length); + + void changeLengthBy(GLfloat delta); + + /** + * \brief Returns the length of the line. + * \details Returns the value of the myLength instance variable. + * \return Length of the Line. + */ + GLfloat getLength() { return myLength; } + + GLfloat getFirstEndpointX(); + + GLfloat getFirstEndpointY(); + + GLfloat getFirstEndpointZ(); + + GLfloat getSecondEndpointX(); + + GLfloat getSecondEndpointY(); + + GLfloat getSecondEndpointZ(); }; } diff --git a/src/TSGL/Polygon.cpp b/src/TSGL/Polygon.cpp deleted file mode 100644 index 3b1ac4a83..000000000 --- a/src/TSGL/Polygon.cpp +++ /dev/null @@ -1,501 +0,0 @@ -#include "Polygon.h" - -namespace tsgl { - - /*! - * \brief Explicitly constructs a new Polygon. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices the number of vertices the complete Polygon will have. - * \warning An invariant is held where if numVertices is less than 3 then an error message is given. - * \return A new Polygon with a buffer for storing the specified numbered of vertices. - */ -Polygon::Polygon(int numVertices) : Shape() { - attribMutex.lock(); - if (numVertices < 3) { - TsglDebug("Cannot have a polygon with fewer than 3 vertices."); - } - attribMutex.unlock(); -} - -/*! - * \brief This method actually draws the Polygon - * \details Depending on isFilled and hasOutline, draws either a series of connected lines outlining the Polygon or a filled version. - */ -void Polygon::draw() { - if(isFilled) { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); - } - if(hasOutline) { - glBufferData(GL_ARRAY_BUFFER, numberOfOutlineVertices * 6 * sizeof(float), outlineVertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_LINE_LOOP, 0, numberOfOutlineVertices); - } -} - - /*! - * \brief Adds another vertex to a Polygon. - * \details This function initializes the next vertex in the Polygon and adds it to a Polygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Polygon::addVertex(float x, float y, const ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = color.R; - outlineVertices[current + 3] = color.G; - outlineVertices[current + 4] = color.B; - outlineVertices[current + 5] = color.A; - } - current += 6; - if (current == numberOfVertices*6) { - init = true; - attribMutex.lock(); - float minX = 0, maxX = 0; - float minY = 0, maxY = 0; - if(hasOutline) { - minX = maxX = outlineVertices[0]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - minY = maxY = outlineVertices[1]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else if (isFilled) { - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - - myCenterX = (minX+maxX)/2; - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); - - attribMutex.unlock(); - } -} - - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param fillColor The reference variable of the fill color of the vertex. - * \param outlineColor The reference variable of the outline color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Polygon::addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = fillColor.R; - vertices[current + 3] = fillColor.G; - vertices[current + 4] = fillColor.B; - vertices[current + 5] = fillColor.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = outlineColor.R; - outlineVertices[current + 3] = outlineColor.G; - outlineVertices[current + 4] = outlineColor.B; - outlineVertices[current + 5] = outlineColor.A; - } - current += 6; - if (current == numberOfVertices*6) { - init = true; - attribMutex.lock(); - float minX = 0, maxX = 0; - float minY = 0, maxY = 0; - if(hasOutline) { - minX = maxX = outlineVertices[0]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - minY = maxY = outlineVertices[1]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else if (isFilled) { - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - - myCenterX = (minX+maxX)/2; - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); - - attribMutex.unlock(); - } -} - -/** - * \brief Sets the Polygon to a new color. - * \param c The new ColorFloat. - */ -void Polygon::setColor(ColorFloat c) { - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = c.R; - outlineVertices[i*6 + 3] = c.G; - outlineVertices[i*6 + 4] = c.B; - outlineVertices[i*6 + 5] = c.A; - } - } -} - -/** - * \brief Sets the Polygon to an array of new colors. - * \param c An array of new ColorFloats. - */ -void Polygon::setColor(ColorFloat c[]) { - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = c[i].R; - outlineVertices[i*6 + 3] = c[i].G; - outlineVertices[i*6 + 4] = c[i].B; - outlineVertices[i*6 + 5] = c[i].A; - } - } -} - -/** - * \brief Sets the Polygon to new single fill and outline colors. - * \param fillColor A new ColorFloat for the Polygon's fill. - * \param outlineColor A new ColorFloat for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor, ColorFloat outlineColor) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor.R; - vertices[i*6 + 3] = fillColor.G; - vertices[i*6 + 4] = fillColor.B; - vertices[i*6 + 5] = fillColor.A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor.R; - outlineVertices[i*6 + 3] = outlineColor.G; - outlineVertices[i*6 + 4] = outlineColor.B; - outlineVertices[i*6 + 5] = outlineColor.A; - } -} - -/** - * \brief Gives the Polygon a new monocolored fill and multicolored outline. - * \param fillColor A new ColorFloat for the Polygon's fill. - * \param outlineColor A new array of ColorFloats for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor, ColorFloat outlineColor[]) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor.R; - vertices[i*6 + 3] = fillColor.G; - vertices[i*6 + 4] = fillColor.B; - vertices[i*6 + 5] = fillColor.A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor[i].R; - outlineVertices[i*6 + 3] = outlineColor[i].G; - outlineVertices[i*6 + 4] = outlineColor[i].B; - outlineVertices[i*6 + 5] = outlineColor[i].A; - } -} - -/** - * \brief Gives the Polygon a new multicolored fill and monocolored outline. - * \param fillColor A new array of ColorFloats for the Polygon's fill. - * \param outlineColor A new ColorFloat for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor[], ColorFloat outlineColor) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor[i].R; - vertices[i*6 + 3] = fillColor[i].G; - vertices[i*6 + 4] = fillColor[i].B; - vertices[i*6 + 5] = fillColor[i].A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor.R; - outlineVertices[i*6 + 3] = outlineColor.G; - outlineVertices[i*6 + 4] = outlineColor.B; - outlineVertices[i*6 + 5] = outlineColor.A; - } -} - -/** - * \brief Sets the Polygon to new single fill and outline colors. - * \param fillColor A new array of ColorFloats for the Polygon's fill. - * \param outlineColor A new array of ColorFloats for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor[], ColorFloat outlineColor[]) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor[i].R; - vertices[i*6 + 3] = fillColor[i].G; - vertices[i*6 + 4] = fillColor[i].B; - vertices[i*6 + 5] = fillColor[i].A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor[i].R; - outlineVertices[i*6 + 3] = outlineColor[i].G; - outlineVertices[i*6 + 4] = outlineColor[i].B; - outlineVertices[i*6 + 5] = outlineColor[i].A; - } -} - -/** - * \brief Gets an array of the Polygon's fill vertex colors. - * \return c An array of ColorFloats. - * \warning This method allocates memory. The caller is responsible for deallocating it. - */ -ColorFloat* Polygon::getFillColor() { - ColorFloat * c = new ColorFloat[numberOfVertices]; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); - } - } else { - TsglErr("Polygon isn't filled."); - for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(1.0f, 1.0f, 1.0f, 1.0f); - } - } - return c; -} - -/** - * \brief Gets an array of the Polygon's fill vertex colors. - * \return c An array of ColorFloats. - * \warning This method allocates memory. The caller is responsible for deallocating it. - */ -ColorFloat* Polygon::getOutlineColor() { - ColorFloat * c = new ColorFloat[numberOfOutlineVertices]; - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - c[i] = ColorFloat(outlineVertices[i*6 + 2], outlineVertices[i*6 + 3], outlineVertices[i*6 + 4], outlineVertices[i*6 + 5]); - } - } else { - TsglErr("Polygon isn't outlined."); - for(int i = 0; i < numberOfOutlineVertices; i++) { - c[i] = ColorFloat(1.0f, 1.0f, 1.0f, 1.0f); - } - } - return c; -} - -/** - * \brief Alters the Polygon's vertex locations. - * \param deltaX The difference between the new and old vertex X coordinates. - * \param deltaY The difference between the new and old vertex Y coordinates. - * \warning This will also alter the Polygon's rotation point if and only if the - * old rotation point was at the Polygon's old center. - */ -void Polygon::moveShapeBy(float deltaX, float deltaY) { - attribMutex.lock(); - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6] += deltaX; //Transpose x - outlineVertices[(i*6)+1] += deltaY; //Transpose y - } - } - myCenterX += deltaX; - myCenterY += deltaY; - attribMutex.unlock(); -} - -/** - * \brief Moves the Polygon to new coordinates. - * \param x The new center x coordinate. - * \param y The new center y coordinate. - * \warning This will also alter the Polygon's rotation point if and only if the - * old rotation point was at the Polygon's old center. - */ -void Polygon::setCenter(float x, float y) { - float deltaX = x - myCenterX; //Change for x - float deltaY = y - myCenterY; //Change for y - attribMutex.lock(); - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - setRotationPoint(x,y); - } - myCenterX = x; - myCenterY = y; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6] += deltaX; //Transpose x - outlineVertices[(i*6)+1] += deltaY; //Transpose y - } - } - attribMutex.unlock(); -} - - -/*! - * \brief Mutator for the rotation of the Polygon. - * \details Rotates the Polygon vertices around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Polygon. - */ -void Polygon::setRotation(float radians) { - if(radians != currentRotation) { - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - float x = vertices[6*i]; - float y = vertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - vertices[6*i] = x; - vertices[6*i+1] = y; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - float x = outlineVertices[6*i]; - float y = outlineVertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - outlineVertices[6*i] = x; - outlineVertices[6*i+1] = y; - } - } - } -} - -/*! - * \brief Destructor for the Polygon. - */ -Polygon::~Polygon() { - if(hasOutline) { - delete[] outlineVertices; - } - if(isFilled) { - delete[] vertices; - } -} - -} \ No newline at end of file diff --git a/src/TSGL/Polygon.h b/src/TSGL/Polygon.h deleted file mode 100644 index 034311938..000000000 --- a/src/TSGL/Polygon.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Polygon.h extends Shape and provides a class for drawing a polygon. - */ - -#ifndef POLYGON_H_ -#define POLYGON_H_ - -#include "Shape.h" // For extending our Shape object -#include "TsglAssert.h" // For unit testing purposes - -namespace tsgl { - -/*! \class Polygon - * \brief Draw an arbitrary Convex polygon with colored vertices. - * \details Polygon is a class for holding vertex data for a Shape with at least three vertices. - * \note Polygon is abstract, and must be extended. - * \details Vertices are drawn in triangle strip format, where the first three vertices make up the first triangle, - * the next vertex plus the previous two make up the second triangle, and so on. - * \details This method is optimized for long lists and offers a marked improvement over drawing individual Triangle instances. - * \note The addVertex() method must be called the same number of times as specified in the constructor. - * \note Calling addVertex() after all vertices have been added will do nothing. - */ -class Polygon : public Shape { -protected: - bool isFilled = true; - bool hasOutline = false; - float* outlineVertices; - int numberOfOutlineVertices; -public: - - Polygon(int numVertices); - - virtual ~Polygon(); - - virtual void draw(); - - virtual void addVertex(float x, float y, const ColorFloat &color = BLACK); - - virtual void addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor); - - virtual void setColor(ColorFloat c); - - virtual void setColor(ColorFloat c[]); - - virtual void setColor(ColorFloat fillColor, ColorFloat outlineColor); - - virtual void setColor(ColorFloat fillColor, ColorFloat outlineColor[]); - - virtual void setColor(ColorFloat fillColor[], ColorFloat outlineColor); - - virtual void setColor(ColorFloat fillColor[], ColorFloat outlineColor[]); - - virtual ColorFloat* getFillColor(); - - virtual ColorFloat* getOutlineColor(); - - virtual void moveShapeBy(float deltaX, float deltaY); - - virtual void setCenter(float x, float y); - - virtual void setRotation(float radians); -}; - -} - -#endif /* POLYGON_H_ */ \ No newline at end of file diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index c5c54a99d..5340df4c2 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -5,66 +5,204 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices) : Shape() { +Polyline::Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll) : Drawable(x,y,z,yaw,pitch,roll) { if (numVertices < 2) TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; - geometryType = GL_LINE_STRIP; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 7]; + attribMutex.unlock(); } /*! * \brief Explicitly constructs a new monocolored Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. - * \param x Array of x positions for the Polyline vertices. - * \param y Array of y positions for the Polyline vertices. - * \param color Color of the Polyline. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param lineVertices An array of vertices for the Polyline. 3 floats * numVertices, x-y-z. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. + * \param color Color of the Polyline, as a ColorFloat. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices, int x[], int y[], ColorFloat color) { +Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color) : Drawable(x,y,z,yaw,pitch,roll) { if (numVertices < 2) - TsglDebug("Cannot have a line with fewer than 2 vertices."); + TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; - geometryType = GL_LINE_STRIP; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 7]; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color); } } /*! * \brief Explicitly constructs a new multicolored Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. - * \param x Array of x positions for the Polyline vertices. - * \param y Array of y positions for the Polyline vertices. - * \param color Color of the Polyline. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param lineVertices An array of vertices for the Polyline. 3 floats * numVertices, x-y-z. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. + * \param color Array of ColorFloats for the Polyline; 1 ColorFloat per vertex. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices, int x[], int y[], ColorFloat color[]) { +Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]) : Drawable(x,y,z,yaw,pitch,roll) { if (numVertices < 2) - TsglDebug("Cannot have a line with fewer than 2 vertices."); + TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; - geometryType = GL_LINE_STRIP; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 7]; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color[i]); + } +} + +/*! + * \brief Draw the Polyline. + * \details This function actually draws the Polyline to the Canvas. + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the Polyline cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). + */ +void Polyline::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_LINE_STRIP, 0, numberOfVertices); +} + + /*! + * \brief Adds another vertex to a Polyline. + * \details This function initializes the next vertex in the Polyline and adds it to a Polyline buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Polyline::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { + if (init) { + TsglDebug("Cannot add anymore vertices."); + return; } + attribMutex.lock(); + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + vertices[currentVertex + 3] = color.R; + vertices[currentVertex + 4] = color.G; + vertices[currentVertex + 5] = color.B; + vertices[currentVertex + 6] = color.A; + currentVertex += 7; + myAlpha += color.A; + if (currentVertex == numberOfVertices*7) { + myAlpha /= numberOfVertices; + init = true; + } + attribMutex.unlock(); } +/** + * \brief Sets the Polyline to a new color. + * \param c The new ColorFloat. + */ +void Polyline::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c.R; + vertices[i*7 + 4] = c.G; + vertices[i*7 + 5] = c.B; + vertices[i*7 + 6] = c.A; + } + myAlpha = c.A; + attribMutex.unlock(); +} + +/** + * \brief Sets the Polyline to a new array of colors. + * \param c The new array of ColorFloats. + */ +void Polyline::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c[i].R; + vertices[i*7 + 4] = c[i].G; + vertices[i*7 + 5] = c[i].B; + vertices[i*7 + 6] = c[i].A; + myAlpha += c[i].A; + } + myAlpha /= numberOfVertices; + attribMutex.unlock(); +} + +/** + * \brief Accessor for Shape's color. + * \details Returns the color of Shape's first vertex. + * \note For multicolored Shapes, use getColors() to access a vector of all relevant colors. + */ +ColorFloat Polyline::getColor() { + attribMutex.lock(); + ColorFloat c = ColorFloat(vertices[3], vertices[4], vertices[5], vertices[6]); + attribMutex.unlock(); + return c; +} + +/** + * \brief Accessor for Shape's colors. + * \details Populates the reference parameter vector with a ColorFloat for each vertex of Shape. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Shape will be pushed. + */ +void Polyline::getColors(std::vector &colorVec) { + attribMutex.lock(); + for (int i = 0; i < numberOfVertices; i++) { + colorVec.push_back(ColorFloat(vertices[i*7+3],vertices[i*7+4],vertices[i*7+5],vertices[i*7+6])); + } + attribMutex.unlock(); +} + + /*! - * \brief Overrides isProcessed() in Shape.h - * \details Overrides Shape::isProcessed() to include invariant. + * \brief Overrides isProcessed() in Drawable.h + * \details Overrides Drawable::isProcessed() to include invariant. */ bool Polyline::isProcessed() { if (numberOfVertices < 2) { diff --git a/src/TSGL/Polyline.h b/src/TSGL/Polyline.h index 2e74da147..42a9751a0 100755 --- a/src/TSGL/Polyline.h +++ b/src/TSGL/Polyline.h @@ -5,7 +5,7 @@ #ifndef POLYLINE_H_ #define POLYLINE_H_ -#include "Shape.h" // For extending our Shape object +#include "Drawable.h" // For extending our Drawable object namespace tsgl { @@ -14,27 +14,31 @@ namespace tsgl { * \details Polyline is a class for holding vertex data for multiple lines whose endpoints are connected. * \details This method is optimized for long lists and offers a marked improvement over drawing individual * Line instances. - * \note The addVertex() method must be called the same number of times as specified in the constructor. + * \note The addVertex() method must be called the same number of times as specified in the constructor, unless a float array is also passed. * \note Calling addVertex() after all vertices have been added will do nothing. - * \note Calling draw() before all vertices have been added will do nothing. + * \note Calling Drawable::draw() before all vertices have been added will do nothing. */ -class Polyline : public Shape { - private: +class Polyline : public Drawable { + protected: + int numberOfVertices; + int currentVertex = 0; + virtual void addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll); public: - Polyline(int numVertices); + Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color); - Polyline(int numVertices, int x[], int y[], ColorFloat color); + Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]); - Polyline(int numVertices, int x[], int y[], ColorFloat color[]); + virtual void draw(Shader * shader); - bool isProcessed(); + virtual void setColor(ColorFloat c); + virtual void setColor(ColorFloat c[]); + virtual ColorFloat getColor(); + virtual void getColors(std::vector &colorVec); - /*! - * \brief Destructor for the Polyline. - */ - ~Polyline() { delete[] vertices; } + bool isProcessed(); }; } diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp new file mode 100644 index 000000000..72a7be951 --- /dev/null +++ b/src/TSGL/Prism.cpp @@ -0,0 +1,262 @@ +#include "Prism.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Prism. + * \details Explicit constructor for a Prism object. + * \param x The x coordinate of the center of the Prism. + * \param y The y coordinate of the center of the Prism. + * \param z The z coordinate of the center of the Prism. + * \param sides The number of sides of the Prism's base. + * \param yaw The Prism's yaw. + * \param pitch The Prism's pitch. + * \param roll The Prism's roll. + * \param c A ColorFloat for the Prism's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. + * \return A new Prism with a buffer for storing the specified numbered of vertices. + */ +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { + if (radius <= 0 || height <= 0 || sides < 3) { + TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myZScale = radius; + myHeight = height; + myYScale = height; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 12; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 6; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < mySides; i++) { + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); + addVertex(0,0.5,0, c); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); + + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); + + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(0,-0.5,0, c); + } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 * 2 / 3; + } +} + + /*! + * \brief Explicitly constructs a new Prism. + * \details Explicit constructor for a Prism object. + * \param x The x coordinate of the center of the Prism. + * \param y The y coordinate of the center of the Prism. + * \param z The z coordinate of the center of the Prism. + * \param sides The number of sides of the Prism's base. + * \param yaw The Prism's yaw. + * \param pitch The Prism's pitch. + * \param roll The Prism's roll. + * \param c An array of ColorFloats for the Prism's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. + * \return A new Prism with a buffer for storing the specified numbered of vertices. + */ +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { + if (radius <= 0 || height <= 0 || sides < 3) { + TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myZScale = radius; + myHeight = height; + myYScale = height; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 12; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 6; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < mySides; i++) { + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[1]); + addVertex(0,0.5,0, c[0]); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[1]); + + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[2]); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[2]); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[2]); + + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[2]); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[2]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[2]); + + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[3]); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[3]); + addVertex(0,-0.5,0, c[4]); + } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 * 2 / 3; + } +} + +/** + * \brief Mutates the distance from the Prism's bottom to its top. + * \param height The Prism's new height. + */ +void Prism::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight = height; + myYScale = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Prism's bottom to its top by the parameter amount. + * \param delta The amount by which to change the height of the Prism. + */ +void Prism::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Prism's base to the corners. + * \param radius The Prism's new radius. + */ +void Prism::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myZScale = radius; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Prism's base to the corner by the parameter amount. + * \param delta The amount by which to change the radius of the Prism. + */ +void Prism::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + myXScale += delta; + myZScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutator. Sets the Prism to a new array of colors. + * \param c The array of new ColorFloats. + * \details The array should have 5 ColorFloats minimum: for the top middle, top outside, sides, bottom outside, and bottom middle respectively. + */ +void Prism::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; + for (int i = 0; i < mySides; i++) { + vertices[i*84+3] = c[1].R; + vertices[i*84+4] = c[1].G; + vertices[i*84+5] = c[1].B; + vertices[i*84+6] = c[1].A; + + vertices[i*84+10] = c[0].R; + vertices[i*84+11] = c[0].G; + vertices[i*84+12] = c[0].B; + vertices[i*84+13] = c[0].A; + + vertices[i*84+17] = c[1].R; + vertices[i*84+18] = c[1].G; + vertices[i*84+19] = c[1].B; + vertices[i*84+20] = c[1].A; + + vertices[i*84+24] = vertices[i*84+31] = vertices[i*84+38] = vertices[i*84+45] = vertices[i*84+52] = vertices[i*84+59] = c[2].R; + vertices[i*84+25] = vertices[i*84+32] = vertices[i*84+39] = vertices[i*84+46] = vertices[i*84+53] = vertices[i*84+60] = c[2].G; + vertices[i*84+26] = vertices[i*84+33] = vertices[i*84+40] = vertices[i*84+47] = vertices[i*84+54] = vertices[i*84+61] = c[2].B; + vertices[i*84+27] = vertices[i*84+34] = vertices[i*84+41] = vertices[i*84+48] = vertices[i*84+55] = vertices[i*84+62] = c[2].A; + + vertices[i*84+66] = vertices[i*84+73] = c[3].R; + vertices[i*84+67] = vertices[i*84+74] = c[3].G; + vertices[i*84+68] = vertices[i*84+75] = c[3].B; + vertices[i*84+69] = vertices[i*84+76] = c[3].A; + + vertices[i*84+80] = c[4].R; + vertices[i*84+81] = c[4].G; + vertices[i*84+82] = c[4].B; + vertices[i*84+83] = c[4].A; + + myAlpha += c[0].A + c[1].A * 2 + c[2].A * 6 + c[3].A * 2 + c[4].A; + } + myAlpha /= numberOfVertices; + attribMutex.unlock(); +} + +/** + * \brief Accessor for Arrow's colors. + * \details Populates the reference parameter vector with a ColorFloat for each end of Arrow. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Arrow will be pushed. + * \note Overrides Shape::getColors(). + */ +void Prism::getColors(std::vector &colorVec) { + attribMutex.lock(); + colorVec.push_back(ColorFloat(vertices[10],vertices[11],vertices[12],vertices[13])); + colorVec.push_back(ColorFloat(vertices[3],vertices[4],vertices[5],vertices[6])); + colorVec.push_back(ColorFloat(vertices[24],vertices[25],vertices[26],vertices[27])); + colorVec.push_back(ColorFloat(vertices[66],vertices[67],vertices[68],vertices[69])); + colorVec.push_back(ColorFloat(vertices[80],vertices[81],vertices[82],vertices[83])); + attribMutex.unlock(); +} + +} \ No newline at end of file diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h new file mode 100644 index 000000000..2f96118bc --- /dev/null +++ b/src/TSGL/Prism.h @@ -0,0 +1,56 @@ +/* + * Prism.h extends Shape and provides a class for drawing a prism. + */ + +#ifndef PRISM_H_ +#define PRISM_H_ + +#include "Shape.h" // For extending our Shape object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Prism + * \brief Draw an arbitrary Prism with colored vertices. + * \details Prism is a class for holding vertex data for a Prism with a base with at least 3 sides. + */ +class Prism : public Shape { +protected: + GLfloat myHeight; + GLfloat myRadius; + int mySides; +public: + Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c); + + Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setHeight(GLfloat height); + + virtual void changeHeightBy(GLfloat delta); + + virtual void setRadius(GLfloat radius); + + virtual void changeRadiusBy(GLfloat delta); + + /*! + * \brief Accessor for the radius of the Prism. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + virtual GLfloat getRadius() { return myRadius; } + + /*! + * \brief Accessor for the height of the Prism. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ + virtual GLfloat getHeight() { return myHeight; } + + virtual void setColor(ColorFloat c) { Shape::setColor(c); } + + virtual void setColor(ColorFloat c[]); + + virtual void getColors(std::vector &colorVec); +}; + +} + +#endif /* PRISM_H_ */ \ No newline at end of file diff --git a/src/TSGL/ProgressBar.cpp b/src/TSGL/ProgressBar.cpp index 51ca3288c..c1a4c3606 100644 --- a/src/TSGL/ProgressBar.cpp +++ b/src/TSGL/ProgressBar.cpp @@ -14,18 +14,36 @@ namespace tsgl { * \param numSegments The number of segments in the progress bar * \return A new ProgressBar with the specified coordinates, maximum dimensions, value range, and segments. */ -ProgressBar::ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments) { +ProgressBar::ProgressBar(float x, float y, float z, float width, float height, float minValue, float maxValue, unsigned numSegments, float yaw, float pitch, float roll) +: Drawable(x, y, z, yaw, pitch, roll) { + shaderType = SHAPE_SHADER_TYPE; + segRecs = new Rectangle*[numSegments]; + segBorders = new Polyline*[numSegments]; startX = new float[numSegments]; endX = new float[numSegments]; min = minValue; max = maxValue; - xx = x; yy = y; myWidth = width; myHeight = height; segs = numSegments; - startX[0] = x; endX[0] = x + myWidth/segs; + startX[0] = -myWidth / 2; endX[0] = startX[0] + myWidth/segs; for (int i = 1; i < segs; ++i) { startX[i] = endX[i-1]; endX[i] = startX[i] + myWidth/segs; } + + // all Polylines can have the same vertices; different locations will be handled with draw() + vertices = new float[15]; + vertices[0] = -(myWidth/segs)/2; vertices[1] = myHeight/2; vertices[2] = 0; + vertices[3] = -(myWidth/segs)/2; vertices[4] = -myHeight/2; vertices[5] = 0; + vertices[6] = (myWidth/segs)/2; vertices[7] = -myHeight/2; vertices[8] = 0; + vertices[9] = (myWidth/segs)/2; vertices[10] = myHeight/2; vertices[11] = 0; + vertices[12] = -(myWidth/segs)/2; vertices[13] = myHeight/2; vertices[14] = 0; + for (int i = 0; i < segs; i++) { + segBorders[i] = new Polyline(0,0,0,5,vertices,yaw,pitch,roll,BLACK); + segRecs[i] = new Rectangle(0,0,0,myWidth/segs,myHeight,yaw,pitch,roll,Colors::highContrastColor(i)); + segRecs[i]->setIsOutlined(false); + } + + init = true; } /*! @@ -35,6 +53,24 @@ ProgressBar::ProgressBar(int x, int y, int width, int height, float minValue, fl */ ProgressBar::~ProgressBar() { delete [] startX; delete [] endX; + for (int i = 0; i < segs; i++) { + delete segBorders[i]; + delete segRecs[i]; + } + delete [] segBorders; delete [] segRecs; +} + +void ProgressBar::draw(Shader * shader) { + for (int i = 0; i < segs; i++) { + segBorders[i]->setCenter(myCenterX + (myWidth/segs) * ( (float)i - (float)(segs-1)/2), myCenterY, myCenterZ); + segRecs[i]->setCenter(myCenterX + (myWidth/segs) * ( (float)i - (float)(segs)/2) + segRecs[i]->getWidth()/2, myCenterY, myCenterZ); + segBorders[i]->setRotationPoint(myCenterX, myCenterY, myCenterZ); + segRecs[i]->setRotationPoint(myCenterX, myCenterY, myCenterZ); + segBorders[i]->setYawPitchRoll(myCurrentYaw, myCurrentPitch, myCurrentRoll); + segRecs[i]->setYawPitchRoll(myCurrentYaw, myCurrentPitch, myCurrentRoll); + segRecs[i]->draw(shader); + segBorders[i]->draw(shader); + } } /*! @@ -56,32 +92,8 @@ void ProgressBar::update(float newValue, int segnum) { float end = start + d/segs; clamp(newValue,start,end); float percent = (newValue-start) / (end-start); - endX[segnum] = startX[segnum]+percent*(myWidth/segs); + segRecs[segnum]->setWidth(percent*(myWidth/segs)); } - /*! - * \brief Accessor for the ProgressBar's representative Polyline array. - * \param index Index of the segment to access. - * \return A pointer to the Polyline array representing segment border i of the ProgressBar. - */ -Polyline* ProgressBar::getBorder(int index) { - int y2 = yy+myHeight; - Polyline* p = new Polyline(5); - p->addVertex(startX[index],yy,BLACK); - p->addVertex(startX[index]+myWidth/segs,yy,BLACK); - p->addVertex(startX[index]+myWidth/segs,y2,BLACK); - p->addVertex(startX[index],y2,BLACK); - p->addVertex(startX[index],yy,BLACK); - return p; -} - - /*! - * \brief Accessor for the ProgressBar's representative Rectangle array. - * \param index Index of the segment to access. - * \return A pointer to the Rectangle array representing segment i of the ProgressBar. - */ -Rectangle* ProgressBar::getRect(int index) { - return new Rectangle(startX[index], yy, endX[index]-startX[index], myHeight, Colors::highContrastColor(index)); -} } diff --git a/src/TSGL/ProgressBar.h b/src/TSGL/ProgressBar.h index 184afd757..2c246d842 100755 --- a/src/TSGL/ProgressBar.h +++ b/src/TSGL/ProgressBar.h @@ -9,6 +9,7 @@ #include "Polyline.h" #include "Rectangle.h" +#include "Drawable.h" namespace tsgl { @@ -18,22 +19,24 @@ namespace tsgl { * ProgressBar is formed of multiple segments, each of which is thread-safe and updated individually * with the update() method. A ProgressBar can be drawn to the screen using Canvas::drawProgress(). */ -class ProgressBar { +class ProgressBar : public Drawable { private: - float *startX, *endX; - float min, max; - int xx, yy, myWidth, myHeight, segs; + Rectangle ** segRecs; + Polyline ** segBorders; + float *startX; + float *endX; + float min, max; + float myWidth, myHeight; + int segs; public: - ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments); + ProgressBar(float x, float y, float z, float width, float height, float minValue, float maxValue, unsigned numSegments, float yaw, float pitch, float roll); ~ProgressBar(); - void update(float newValue, int segnum = -1); - - Polyline* getBorder(int index); + void draw(Shader * shader); - Rectangle* getRect(int index); + void update(float newValue, int segnum = -1); /*! * \brief Accessor for the ProgressBar's number of segments @@ -42,17 +45,16 @@ class ProgressBar { int getSegs() { return segs; } /*! - * \brief Accessor for a segment's x position - * \param i Index of the segment - * \return The x-coordinate of the left edge of segment i in the ProgressBar. + * \brief Accessor for the ProgressBar's width in pixels + * \return The pixel width of the ProgressBar. */ - int getSegX(int i) { return startX[i]; } + float getWidth() { return myWidth; } /*! - * \brief Accessor for a segment's y position - * \return The y-coordinate of the top edge of the ProgressBar. + * \brief Accessor for the ProgressBar's height in pixels + * \return The pixel height of the ProgressBar. */ - int getSegY() { return yy; } + float getHeight() { return myHeight; } }; } diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp new file mode 100644 index 000000000..bef08bade --- /dev/null +++ b/src/TSGL/Pyramid.cpp @@ -0,0 +1,269 @@ +#include "Pyramid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Pyramid. + * \details Explicit constructor for a Pyramid object. + * \param x The x coordinate of the center of the Pyramid. + * \param y The y coordinate of the center of the Pyramid. + * \param z The z coordinate of the center of the Pyramid. + * \param height The distance from the center of the base to tip of the Pyramid. + * \param radius The distance from the center of the Pyramid's base to each vertex of the base. + * \param sides The number of sides of the Pyramid's base. + * \param yaw The Pyramid's yaw. + * \param pitch The Pyramid's pitch. + * \param roll The Pyramid's roll. + * \param c A ColorFloat for the Pyramid's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Pyramid with a buffer for storing the specified numbered of vertices. + */ +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { + if (sides < 3) { + TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); + } + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Pyramid with radius or height less than or equal to 0."); + } + attribMutex.lock(); + myHeight = height; + myYScale = height; + myRadius = radius; + myXScale = radius; + myZScale = radius; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 6; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 4; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < mySides; i++) { + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(0,-0.5,0, c); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); + + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(0,0.5,0, ColorFloat(c.R*.5,c.G*.5,c.B*.5,c.A)); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); + } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 2 - 14; + + addOutlineVertex(0, 0.5, 0, GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 / 2; + } +} + + /*! + * \brief Explicitly constructs a new Pyramid. + * \details Explicit constructor for a Pyramid object. + * \param x The x coordinate of the center of the Pyramid. + * \param y The y coordinate of the center of the Pyramid. + * \param z The z coordinate of the center of the Pyramid. + * \param height The distance from the center of the base to tip of the Pyramid. + * \param radius The distance from the center of the Pyramid's base to each vertex of the base. + * \param sides The number of sides of the Pyramid's base. + * \param yaw The Pyramid's yaw. + * \param pitch The Pyramid's pitch. + * \param roll The Pyramid's roll. + * \param c An array of ColorFloats for the Pyramid's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Pyramid with a buffer for storing the specified numbered of vertices. + */ +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { + if (sides < 3) { + TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); + } + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Pyramid with radius or height less than or equal to 0."); + } + attribMutex.lock(); + myHeight = height; + myYScale = height; + myRadius = radius; + myXScale = radius; + myZScale = radius; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 6; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 4; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + attribMutex.unlock(); + for (int i = 0; i < mySides; i++) { + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[i+1]); + addVertex(0,-0.5,0, c[mySides+1]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[(i+1) % mySides + 1]); + + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[i+1]); + addVertex(0,0.5,0, c[0]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[(i+1) % mySides + 1]); + } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 2 - 14; + + addOutlineVertex(0, 0.5, 0, GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 / 2; + } +} + +/** + * \brief Mutates the Pyramid's base's radius. + * \param radius The new radius of the Pyramid's base. + */ +void Pyramid::setRadius(float radius) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius = radius; + myXScale = radius; + myZScale = radius; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Pyramid's base's radius by the parameter amount. + * \param delta The amount by which to change the radius of the Pyramid's base. + */ +void Pyramid::changeRadiusBy(float delta) { + attribMutex.lock(); + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius += delta; + myXScale += delta; + myZScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Pyramid's base to the tip. + * \param height The Pyramid's new height. + */ +void Pyramid::setHeight(float height) { + if (height <= 0) { + TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight = height; + myYScale = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Pyramid's base to the tip by the parameter amount. + * \param delta The amount by which to change the height of the pyramid. + */ +void Pyramid::changeHeightBy(float delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Sets the Pyramid to a new color. + * \param c The new ColorFloat. + */ +void Pyramid::setColor(ColorFloat c) { + attribMutex.lock(); + myAlpha = c.A; + for(int i = 0; i < mySides; i++) { + vertices[i*42 + 3] = vertices[i*42 + 10] = vertices[i*42 + 17] = vertices[i*42 + 24] = vertices[i*42 + 38] = c.R; + vertices[i*42 + 4] = vertices[i*42 + 11] = vertices[i*42 + 18] = vertices[i*42 + 25] = vertices[i*42 + 39] = c.G; + vertices[i*42 + 5] = vertices[i*42 + 12] = vertices[i*42 + 19] = vertices[i*42 + 26] = vertices[i*42 + 40] = c.B; + vertices[i*42 + 6] = vertices[i*42 + 13] = vertices[i*42 + 20] = vertices[i*42 + 27] = vertices[i*42 + 41] = c.A; + + vertices[i*42 + 31] = c.R *.5; + vertices[i*42 + 32] = c.G *.5; + vertices[i*42 + 33] = c.B *.5; + vertices[i*42 + 34] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Pyramid to an array of new colors. + * \param c An array of new ColorFloats. + * \details The array should have mySides+2 ColorFloats minimum. + */ +void Pyramid::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; + for(int i = 0; i < mySides; i++) { + vertices[i*42 + 3] = c[i+1].R; + vertices[i*42 + 4] = c[i+1].G; + vertices[i*42 + 5] = c[i+1].B; + vertices[i*42 + 6] = c[i+1].A; + + vertices[i*42 + 10] = c[mySides+1].R; + vertices[i*42 + 11] = c[mySides+1].G; + vertices[i*42 + 12] = c[mySides+1].B; + vertices[i*42 + 13] = c[mySides+1].A; + + vertices[i*42 + 17] = c[(i+1) % mySides + 1].R; + vertices[i*42 + 18] = c[(i+1) % mySides + 1].G; + vertices[i*42 + 19] = c[(i+1) % mySides + 1].B; + vertices[i*42 + 20] = c[(i+1) % mySides + 1].A; + + vertices[i*42 + 24] = c[i+1].R; + vertices[i*42 + 25] = c[i+1].G; + vertices[i*42 + 26] = c[i+1].B; + vertices[i*42 + 27] = c[i+1].A; + + vertices[i*42 + 31] = c[0].R; + vertices[i*42 + 32] = c[0].G; + vertices[i*42 + 33] = c[0].B; + vertices[i*42 + 34] = c[0].A; + + vertices[i*42 + 38] = c[(i+1) % mySides + 1].R; + vertices[i*42 + 39] = c[(i+1) % mySides + 1].G; + vertices[i*42 + 40] = c[(i+1) % mySides + 1].B; + vertices[i*42 + 41] = c[(i+1) % mySides + 1].A; + + myAlpha += c[i+1].A * 2 + c[0].A + c[(i+1) % mySides + 1].A * 2 + c[mySides+2].A; + } + myAlpha /= numberOfVertices; + attribMutex.unlock(); +} + +/** + * \brief Accessor for Arrow's colors. + * \details Populates the reference parameter vector with a ColorFloat for each end of Arrow. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Arrow will be pushed. + * \note Overrides Shape::getColors(). + */ +void Pyramid::getColors(std::vector &colorVec) { + attribMutex.lock(); + colorVec.push_back(ColorFloat(vertices[31],vertices[32],vertices[33],vertices[34])); + for (int i = 0; i < mySides; i++) { + colorVec.push_back(ColorFloat(vertices[42*i+3],vertices[42*i+4],vertices[42*i+5],vertices[42*i+6])); + } + colorVec.push_back(ColorFloat(vertices[10],vertices[11],vertices[12],vertices[13])); + attribMutex.unlock(); +} + +} \ No newline at end of file diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h new file mode 100644 index 000000000..82f47d8c1 --- /dev/null +++ b/src/TSGL/Pyramid.h @@ -0,0 +1,56 @@ +/* + * Pyramid.h extends Shape and provides a class for drawing a pyramid. + */ + +#ifndef PYRAMID_H_ +#define PYRAMID_H_ + +#include "Shape.h" // For extending our Shape object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Pyramid + * \brief Draw an arbitrary Pyramid with colored vertices. + * \details Pyramid is a class for holding vertex data for a pyramid with a base with at least 3 sides. + */ +class Pyramid : public Shape { +protected: + GLfloat myHeight; + GLfloat myRadius; + int mySides; +public: + Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c); + + Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setRadius(float radius); + + virtual void changeRadiusBy(float delta); + + virtual void setHeight(float height); + + virtual void changeHeightBy(float delta); + + /*! + * \brief Accessor for the height of the Prism. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ + virtual GLfloat getHeight() { return myHeight; } + + /*! + * \brief Accessor for the radius of the Prism. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + virtual GLfloat getRadius() { return myRadius; } + + virtual void setColor(ColorFloat c); + + virtual void setColor(ColorFloat c[]); + + virtual void getColors(std::vector &colorVec); +}; + +} + +#endif /* PYRAMID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Rectangle.cpp b/src/TSGL/Rectangle.cpp index bd3053f34..9788c7c07 100644 --- a/src/TSGL/Rectangle.cpp +++ b/src/TSGL/Rectangle.cpp @@ -3,113 +3,133 @@ namespace tsgl { /*! - * \brief Explicitly constructs a Rectangle with monocolored fill or outline. + * \brief Explicitly constructs a Rectangle with monocolored fill. * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. + * \param x The x coordinate of the Rectangle's center. + * \param y The y coordinate of the Rectangle's center. + * \param z The z coordinate of the Rectangle's center. * \param width The width of the Rectangle. * \param height The height of the Rectangle. + * \param yaw The Rectangle's yaw in 3D space. + * \param pitch The Rectangle's pitch in 3D space. + * \param roll The Rectangle's roll in 3D space. * \param color The color of the Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and color. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat color, bool filled) : ConvexPolygon(4, filled, !filled) { - addVertex(x, y, color); - addVertex(x + width, y, color); - addVertex(x + width, y + height, color); - addVertex(x, y + height, color); +Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + if (height <= 0 || width <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = myWidth = width; + myYScale = myHeight = height; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color); + addVertex(-0.5, -0.5, 0, color); + addVertex(0.5, -0.5, 0, color); + addVertex(0.5, 0.5, 0, color); + + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); } /*! - * \brief Explicitly constructs a Rectangle with multicolored fill or outline. + * \brief Explicitly constructs a Rectangle with multicolored fill. * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. + * \param x The x coordinate of the Rectangle's center. + * \param y The y coordinate of the Rectangle's center. + * \param z The z coordinate of the Rectangle's center. * \param width The width of the Rectangle. * \param height The height of the Rectangle. + * \param yaw The Rectangle's yaw in 3D space. + * \param pitch The Rectangle's pitch in 3D space. + * \param roll The Rectangle's roll in 3D space. * \param color An array of colors for the vertices of the Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and colors. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat color[], bool filled) : ConvexPolygon(4, filled, !filled) { - addVertex(x, y, color[0]); - addVertex(x + width, y, color[1]); - addVertex(x + width, y + height, color[2]); - addVertex(x, y + height, color[3]); +Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + if (height <= 0 || width <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = myWidth = width; + myYScale = myHeight = height; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color[0]); + addVertex(-0.5, -0.5, 0, color[1]); + addVertex(0.5, -0.5, 0, color[2]); + addVertex(0.5, 0.5, 0, color[3]); + + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); } -/*! - * \brief Explicitly constructs a Rectangle with different monocolored fill and outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor The color of the Rectangle's fill - * \param outlineColor The color of the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the left side of the Rectangle base to its right side. + * \param width The Rectangle's new width. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor, outlineColor); - addVertex(x + width, y, fillColor, outlineColor); - addVertex(x + width, y + height, fillColor, outlineColor); - addVertex(x, y + height, fillColor, outlineColor); +void Rectangle::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have a Rectangle with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = width; + myXScale = width; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with multicolored fill and monocolored outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor The color of the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the left side of the Rectangle base to its right side by the parameter amount. + * \param delta The amount by which to change the width of the Rectangle. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor[0], outlineColor); - addVertex(x + width, y, fillColor[1], outlineColor); - addVertex(x + width, y + height, fillColor[2], outlineColor); - addVertex(x, y + height, fillColor[3], outlineColor); +void Rectangle::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have a Rectangle with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth += delta; + myXScale += delta; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with monocolored fill and multicolored outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor The color of the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the top side of the Rectangle base to its bottom side. + * \param height The Rectangle's new height. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor, outlineColor[0]); - addVertex(x + width, y, fillColor, outlineColor[1]); - addVertex(x + width, y + height, fillColor, outlineColor[2]); - addVertex(x, y + height, fillColor, outlineColor[3]); +void Rectangle::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = height; + myYScale = height; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with different multicolored fill and outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the top side of the Rectangle base to its bottom side by the parameter amount. + * \param delta The amount by which to change the height of the Rectangle. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor[0], outlineColor[0]); - addVertex(x + width, y, fillColor[1], outlineColor[1]); - addVertex(x + width, y + height, fillColor[2], outlineColor[2]); - addVertex(x, y + height, fillColor[3], outlineColor[3]); +void Rectangle::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); } } diff --git a/src/TSGL/Rectangle.h b/src/TSGL/Rectangle.h index 651bdc87f..8d5393970 100755 --- a/src/TSGL/Rectangle.h +++ b/src/TSGL/Rectangle.h @@ -15,20 +15,31 @@ namespace tsgl { */ class Rectangle : public ConvexPolygon { private: - + GLfloat myWidth, myHeight; public: + Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color); - Rectangle(float x, float y, float width, float height, const ColorFloat color, bool filled = true); + Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color[]); - Rectangle(float x, float y, float width, float height, const ColorFloat color[], bool filled = true); + /*! + * \brief Accessor for the width of the Rectangle. + * \details Returns the value of the myWidth private variable, a GLfloat. + */ + GLfloat getWidth() { return myWidth; } - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor); + /*! + * \brief Accessor for the height of the Rectangle. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ + GLfloat getHeight() { return myHeight; } - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor); + void setWidth(GLfloat width); - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor[]); + void setHeight(GLfloat height); - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + void changeWidthBy(GLfloat delta); + + void changeHeightBy(GLfloat delta); }; } diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index 7d02cb3d1..c29a68166 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -3,122 +3,88 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new RegularPolygon with monocolored fill or outline. - * \details This function draws a regular polygon with the given center, radius, resolution + * \brief Explicitly constructs a new RegularPolygon with monocolored fill. + * \details This function draws a regular polygon with the given center, sides, radius, rotation, and color. * (number of sides), and color. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). + * \param x The x coordinate of the RegularPolygon's center. + * \param y The y coordinate of the RegularPolygon's center. + * \param z The z coordinate of the RegularPolygon's center. + * \param radius The radius of the RegularPolygon in pixels. + * \param sides The number of sides to use in the RegularPolygon. + * \param yaw The RegularPolygon's yaw in 3D space. + * \param pitch The RegularPolygon's pitch in 3D space. + * \param roll The RegularPolygon's roll in 3D space. + * \param color The color of the RegularPolygon. */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color, bool filled) : ConvexPolygon(sides, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), color); - } +RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / sides * PI; + for (int i = 0; i < sides; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } } /*! - * \brief Explicitly constructs a new RegularPolygon with multicolored fill or outline. - * \details This function draws a regular polygon with the given center, radius, resolution + * \brief Explicitly constructs a new RegularPolygon with multicolored fill. + * \details This function draws a regular polygon with the given center, sides, radius, rotation, and color. * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. + * \param x The x coordinate of the RegularPolygon's center. + * \param y The y coordinate of the RegularPolygon's center. + * \param z The z coordinate of the RegularPolygon's center. + * \param radius The radius of the RegularPolygon in pixels. + * \param sides The number of sides to use in the RegularPolygon. + * \param yaw The RegularPolygon's yaw in 3D space. + * \param pitch The RegularPolygon's pitch in 3D space. + * \param roll The RegularPolygon's roll in 3D space. * \param color An array of colors for the regular polygon's vertices. - * \param filled Whether the regular polygon should be filled - * (set to true by default). */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color[], bool filled) : ConvexPolygon(sides, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), color[i]); - } +RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + mySides = sides; + attribMutex.unlock(); + float delta = 2.0f / sides * PI; + for (int i = 0; i < sides; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } } -/*! - * \brief Explicitly constructs a new RegularPolygon with different monocolored fill and outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param fillColor The color of the regular polygon's fill. - * \param outlineColor The color of the regular polygon's outline. - */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor, outlineColor); - } -} - -/*! - * \brief Explicitly constructs a new RegularPolygon with multicolored fill and monocolored outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor An array of colors for the regular polygon's fill. - * \param outlineColor The color of the regular polygon's outline. +/** + * \brief Mutates the distance from the center of the RegularPolygon base to its vertices. + * \param radius The RegularPolygon's new radius. */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor[i], outlineColor); - } +void RegularPolygon::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a RegularPolygon with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new RegularPolygon with monocolored fill and multicolored outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor The color of the regular polygon's fill. - * \param outlineColor An array of colors for the regular polygon's outline. - */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor, outlineColor[i]); - } -} - -/*! - * \brief Explicitly constructs a new RegularPolygon with different multicolored fill and outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor An array of colors for the regular polygon's fill. - * \param outlineColor An array of colors for the regular polygon's outline. +/** + * \brief Mutates the distance from the center of the RegularPolygon to its vertices by the parameter amount. + * \param delta The amount by which to change the radius of the RegularPolygon. */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor[i], outlineColor[i]); - } +void RegularPolygon::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a RegularPolygon with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/TSGL/RegularPolygon.h b/src/TSGL/RegularPolygon.h index fb3b8ac0e..4d2d44bc8 100644 --- a/src/TSGL/RegularPolygon.h +++ b/src/TSGL/RegularPolygon.h @@ -9,26 +9,35 @@ namespace tsgl { - /*! \class RegularPolygon - * \brief Draw a regular polygon. - * \details RegularPolygon is a class for holding ConvexPolygon data for a regular polygon. - */ - class RegularPolygon : public ConvexPolygon { - public: - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color, bool filled = true); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color[], bool filled = true); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor[]); - - - }; +/*! \class RegularPolygon +* \brief Draw a regular polygon. +* \details RegularPolygon is a class for holding ConvexPolygon data for a regular polygon. +*/ +class RegularPolygon : public ConvexPolygon { +protected: + GLfloat myRadius; + int mySides; +public: + RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color); + + RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color[]); + + /*! + * \brief Accessor for the number of sides of the RegularPolygon. + * \details Returns the value of the mySides private variable, an int. + */ + int getSides() { return mySides; } + + /*! + * \brief Accessor for the radius of the RegularPolygon. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + GLfloat getRadius() { return myRadius; } + + void setRadius(GLfloat radius); + + void changeRadiusBy(GLfloat delta); +}; } diff --git a/src/TSGL/Shader.h b/src/TSGL/Shader.h new file mode 100644 index 000000000..97631e3de --- /dev/null +++ b/src/TSGL/Shader.h @@ -0,0 +1,156 @@ +#ifndef SHADER_H +#define SHADER_H + +#include +#include + +#include +#include +#include +#include + +class Shader +{ +public: + unsigned int ID; + // constructor generates the shader on the fly + // ------------------------------------------------------------------------ + Shader(const char* vertexShader, const char* fragmentShader, const char* geometryShader = nullptr) + { + + GLenum err = glewInit(); + if (err != GLEW_OK) + exit(1); // or handle the error in a nicer way + if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. + exit(1); // or handle the error in a nicer way + // 2. compile shaders + unsigned int vertex, fragment; + // vertex shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vertexShader, NULL); + glCompileShader(vertex); + checkCompileErrors(vertex, "VERTEX"); + // fragment Shader + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fragmentShader, NULL); + glCompileShader(fragment); + checkCompileErrors(fragment, "FRAGMENT"); + // if geometry shader is given, compile geometry shader + unsigned int geometry; + + + if(geometryShader != nullptr) + { + geometry = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(geometry, 1, &geometryShader, NULL); + glCompileShader(geometry); + checkCompileErrors(geometry, "GEOMETRY"); + } + // shader Program + ID = glCreateProgram(); + glAttachShader(ID, vertex); + glAttachShader(ID, fragment); + if(geometryShader != nullptr) + glAttachShader(ID, geometry); + glLinkProgram(ID); + checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessery + glDeleteShader(vertex); + glDeleteShader(fragment); + if(geometryShader != nullptr) + glDeleteShader(geometry); + + } + // activate the shader + // ------------------------------------------------------------------------ + void use() + { + glUseProgram(ID); + } + // utility uniform functions + // ------------------------------------------------------------------------ + void setBool(const std::string &name, bool value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); + } + // ------------------------------------------------------------------------ + void setInt(const std::string &name, int value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setFloat(const std::string &name, float value) const + { + glUniform1f(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setVec2(const std::string &name, const glm::vec2 &value) const + { + glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec2(const std::string &name, float x, float y) const + { + glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); + } + // ------------------------------------------------------------------------ + void setVec3(const std::string &name, const glm::vec3 &value) const + { + glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec3(const std::string &name, float x, float y, float z) const + { + glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); + } + // ------------------------------------------------------------------------ + void setVec4(const std::string &name, const glm::vec4 &value) const + { + glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec4(const std::string &name, float x, float y, float z, float w) + { + glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); + } + // ------------------------------------------------------------------------ + void setMat2(const std::string &name, const glm::mat2 &mat) const + { + glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat3(const std::string &name, const glm::mat3 &mat) const + { + glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat4(const std::string &name, const glm::mat4 &mat) const + { + glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + +private: + // utility function for checking shader compilation/linking errors. + // ------------------------------------------------------------------------ + void checkCompileErrors(GLuint shader, std::string type) + { + GLint success; + GLchar infoLog[1024]; + if(type != "PROGRAM") + { + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + else + { + glGetProgramiv(shader, GL_LINK_STATUS, &success); + if(!success) + { + glGetProgramInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + } +}; +#endif \ No newline at end of file diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index 7bf8bf805..5d10db558 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -11,11 +11,7 @@ namespace tsgl { * \warning You must inherit the parent's constructor if you are extending Shape. * \note Refer to the Shape class description for more details. */ -Shape::Shape() : Drawable() { - isTextured = false; - currentRotation = 0; - myCenterX = myCenterY = 0; -} +Shape::Shape(float x, float y, float z, float yaw, float pitch, float roll) : Drawable(x,y,z,yaw,pitch,roll) { } /*! * \brief Draw the Shape. @@ -24,9 +20,31 @@ Shape::Shape() : Drawable() { * \note A message indicating that the Shape cannot be drawn yet will be given * if the above condition is met (vertex buffer = not full). */ -void Shape::draw() { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); +void Shape::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + if (isFilled) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); + } + + if (isOutlined) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfOutlineVertices * 7, outlineVertices, GL_DYNAMIC_DRAW); + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); + } } /*! @@ -34,52 +52,62 @@ void Shape::draw() { * \details This function initializes the next vertex in the Shape and adds it to a Shape buffer. * \param x The x position of the vertex. * \param y The y position of the vertex. + * \param z The z position of the vertex. * \param color The reference variable of the color of the vertex. * \note This function does nothing if the vertex buffer is already full. * \note A message is given indicating that the vertex buffer is full. */ -void Shape::addVertex(float x, float y, const ColorFloat &color) { +void Shape::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { if (init) { TsglDebug("Cannot add anymore vertices."); return; } - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - current += 6; - if (current == numberOfVertices*6) { + attribMutex.lock(); + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + vertices[currentVertex + 3] = color.R; + vertices[currentVertex + 4] = color.G; + vertices[currentVertex + 5] = color.B; + vertices[currentVertex + 6] = color.A; + currentVertex += 7; + myAlpha += color.A; + if (currentVertex == numberOfVertices*7) { + myAlpha /= numberOfVertices; init = true; - attribMutex.lock(); - - float minX, maxX; - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - myCenterX = (minX+maxX)/2; - - float minY, maxY; - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); + } + attribMutex.unlock(); +} - attribMutex.unlock(); + /*! + * \brief Adds another outline vertex to a Shape. + * \details This function initializes the next vertex in the Shape and adds it to a Shape buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Shape::addOutlineVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { + if (outlineInit) { + TsglDebug("Cannot add anymore vertices."); + printf("added enough already tbh\n"); + return; + } + attribMutex.lock(); + outlineVertices[currentOutlineVertex] = x; + outlineVertices[currentOutlineVertex + 1] = y; + outlineVertices[currentOutlineVertex + 2] = z; + outlineVertices[currentOutlineVertex + 3] = color.R; + outlineVertices[currentOutlineVertex + 4] = color.G; + outlineVertices[currentOutlineVertex + 5] = color.B; + outlineVertices[currentOutlineVertex + 6] = color.A; + currentOutlineVertex += 7; + if (currentOutlineVertex == numberOfOutlineVertices*7) { + outlineInit = true; } + attribMutex.unlock(); } /** @@ -87,12 +115,15 @@ void Shape::addVertex(float x, float y, const ColorFloat &color) { * \param c The new ColorFloat. */ void Shape::setColor(ColorFloat c) { + attribMutex.lock(); + myAlpha = c.A; for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; + vertices[i*7 + 3] = c.R; + vertices[i*7 + 4] = c.G; + vertices[i*7 + 5] = c.B; + vertices[i*7 + 6] = c.A; } + attribMutex.unlock(); } /** @@ -100,90 +131,57 @@ void Shape::setColor(ColorFloat c) { * \param c The new array of ColorFloats. */ void Shape::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; + vertices[i*7 + 3] = c[i].R; + vertices[i*7 + 4] = c[i].G; + vertices[i*7 + 5] = c[i].B; + vertices[i*7 + 6] = c[i].A; + myAlpha += c[i].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } /** - * \brief Alters the Shape's vertex locations. - * \param deltaX The difference between the new and old vertex X coordinates. - * \param deltaY The difference between the new and old vertex Y coordinates. - * \warning This will also alter the Shape's rotation point if and only if the - * old rotation point was at the Shape's old center. + * \brief Sets the Shape's outline to a new color. + * \param c The new ColorFloat. */ -void Shape::moveShapeBy(float deltaX, float deltaY) { +void Shape::setOutlineColor(ColorFloat c) { attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y + for(int i = 0; i < numberOfOutlineVertices; i++) { + outlineVertices[i*7 + 3] = c.R; + outlineVertices[i*7 + 4] = c.G; + outlineVertices[i*7 + 5] = c.B; + outlineVertices[i*7 + 6] = c.A; } - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; attribMutex.unlock(); } /** - * \brief Moves the Shape to new coordinates. - * \param x The new center x coordinate. - * \param y The new center y coordinate. - * \warning This will also alter the Shape's rotation point if and only if the - * old rotation point was at the Shape's old center. + * \brief Accessor for Shape's color. + * \details Returns the color of Shape's first vertex. + * \note For multicolored Shapes, use getColors() to access a vector of all relevant colors. */ -void Shape::setCenter(float x, float y) { - float deltaX = x - myCenterX; //Change for x - float deltaY = y - myCenterY; //Change for y +ColorFloat Shape::getColor() { attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX = x; - myRotationPointY = y; - } - - myCenterX = x; - myCenterY = y; - - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } + ColorFloat c = ColorFloat(vertices[3], vertices[4], vertices[5], vertices[6]); attribMutex.unlock(); + return c; } -/*! - * \brief Mutator for the rotation of the Shape. - * \details Rotates the Shape vertices around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Shape. +/** + * \brief Accessor for Shape's colors. + * \details Populates the reference parameter vector with a ColorFloat for each vertex of Shape. + * \param colorVec A vector of ColorFloats to which the ColorFloats associated with Shape will be pushed. */ -void Shape::setRotation(float radians) { - if(radians != currentRotation) { +void Shape::getColors(std::vector &colorVec) { attribMutex.lock(); - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; - for(int i = 0; i < numberOfVertices; i++) { - float x = vertices[6*i]; - float y = vertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - vertices[6*i] = x; - vertices[6*i+1] = y; + for (int i = 0; i < numberOfVertices; i++) { + colorVec.push_back(ColorFloat(vertices[i*7+3],vertices[i*7+4],vertices[i*7+5],vertices[i*7+6])); } attribMutex.unlock(); - } } } \ No newline at end of file diff --git a/src/TSGL/Shape.h b/src/TSGL/Shape.h index 5eeef2c07..a9c78c22f 100755 --- a/src/TSGL/Shape.h +++ b/src/TSGL/Shape.h @@ -29,33 +29,48 @@ namespace tsgl { class Shape : public Drawable { protected: int numberOfVertices; - float* vertices; + int currentVertex = 0; GLenum geometryType; - bool init = false; - int current = 0; - float currentRotation; - public: - Shape(); + virtual void addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + bool isFilled = true; - virtual void draw(); + int numberOfOutlineVertices; + int currentOutlineVertex = 0; + GLenum outlineGeometryType; + virtual void addOutlineVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + GLfloat * outlineVertices; + bool isOutlined = true; - virtual void addVertex(float x, float y, const ColorFloat &color = BLACK); + bool outlineInit = false; - virtual void setColor(ColorFloat c); + public: + Shape(float x, float y, float z, float yaw, float pitch, float roll); + virtual void draw(Shader * shader); + + virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); + virtual void setOutlineColor(ColorFloat c); + virtual ColorFloat getColor(); + virtual void getColors(std::vector &colorVec); - virtual void moveShapeBy(float deltaX, float deltaY); + virtual bool isProcessed() { return outlineInit && init; } - virtual void setCenter(float x, float y); + /*! \brief Set whether or not the Shape will be filled. + * \details Sets the isFilled instance variable to the value of the parameter. + * \param status Boolean value to which isFilled will be set equivalent. + * \warning Disabling fill on some 3D Shapes, like Cone and Cylinder, can be awkward visually. + */ + virtual void setIsFilled(bool status) { isFilled = status; } - virtual void setRotation(float radians); + /*! \brief Set whether or not the Shape will be outlined. + * \details Sets the isOutlined instance variable to the value of the parameter. + * \param status Boolean value to which isOutlined will be set equivalent. + * \warning Disabling outlines on monocolored 3D Shapes can be awkward visually. + */ + virtual void setIsOutlined(bool status) { isOutlined = status; } - /*! - * \brief Accessor that returns if Shape is processed and ready to be drawn - * \details This function returns true only if all vertices have been inserted into an array. - */ - virtual bool isProcessed() { return init; } + ~Shape() { /* delete [] vertices; */ } }; } diff --git a/src/TSGL/Spectrogram.cpp b/src/TSGL/Spectrogram.cpp index 843dc5daa..04cd9400d 100644 --- a/src/TSGL/Spectrogram.cpp +++ b/src/TSGL/Spectrogram.cpp @@ -16,41 +16,48 @@ const float Spectrogram::PI = 3.149f; * \return A new Spectrogram with the specified drawing mode and size. */ Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { - for (int i = 0; i < NUM_COLORS; ++i) - omp_init_lock(&(writelock[i])); - omp_init_lock(&masterlock); - myWidth = width; - myHeight = (height > 0) ? height : width; - myDrawMode = drawMode; - if (myDrawMode == HORIZONTAL) - myHeight = NUM_COLORS; - else if (myDrawMode == VERTICAL) - myWidth = NUM_COLORS; + for (int i = 0; i < NUM_COLORS; ++i) { + omp_init_lock(&(writelock[i])); + } + omp_init_lock(&masterlock); + myWidth = width; + myHeight = (height > 0) ? height : width; + myDrawMode = drawMode; + if (myDrawMode == HORIZONTAL) + myHeight = NUM_COLORS; + else if (myDrawMode == VERTICAL) + myWidth = NUM_COLORS; - can = new Canvas(-1, 0, myWidth, myHeight ,""); - maxCount = 0; - count[0] = 0; - xx[0] = (myWidth)/2; - yy[0] = (myHeight)/2; - col[0] = WHITE; - black[0] = BLACK; - for (unsigned i = 1; i < NUM_COLORS; ++i) { - count[i] = 0; - xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2; - yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2; - col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); - black[i] = col[i] * 0.25f; - } - count[NUM_COLORS] = 0; - xx[NUM_COLORS] = xx[1]; - yy[NUM_COLORS] = yy[1]; - col[NUM_COLORS] = col[1]; - black[NUM_COLORS] = black[1]; - for (int k = 0; k < NUM_COLORS+1; ++k) { - maxx[k] = xx[k]; - maxy[k] = yy[k]; - } - can->start(); + can = new Canvas(-1, 0, myWidth, myHeight ,""); + maxCount = 0; + count[0] = 0; + xx[0] = (myWidth)/2; + yy[0] = (myHeight)/2; + col[0] = WHITE; + black[0] = BLACK; + centerX = 0; + centerY = 0; + for (unsigned i = 1; i < NUM_COLORS; ++i) { + count[i] = 0; + xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2 - can->getWindowWidth() / 2; + yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2 - can->getWindowHeight() / 2; + col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); + black[i] = col[i] * 0.25f; + centerX += xx[i]; + centerY += yy[i]; + } + centerX /= NUM_COLORS; + centerY /= NUM_COLORS; + count[NUM_COLORS] = 0; + xx[NUM_COLORS] = xx[1]; + yy[NUM_COLORS] = yy[1]; + col[NUM_COLORS] = col[1]; + black[NUM_COLORS] = black[1]; + for (int k = 0; k < NUM_COLORS+1; ++k) { + maxx[k] = xx[k]; + maxy[k] = yy[k]; + } + can->start(); } /*! @@ -59,10 +66,10 @@ Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { * \details Frees up memory that was allocated to a Spectrogram instance. */ Spectrogram::~Spectrogram() { - for (int i = 0; i < NUM_COLORS; ++i) - omp_destroy_lock(&(writelock[i])); - omp_destroy_lock(&masterlock); - delete can; + for (int i = 0; i < NUM_COLORS; ++i) + omp_destroy_lock(&(writelock[i])); + omp_destroy_lock(&masterlock); + delete can; } /*! @@ -75,26 +82,26 @@ Spectrogram::~Spectrogram() { * \param decay Falloff for weight upon adjacent values. */ void Spectrogram::updateLocked(int index, float weight, float decay) { - int i = index % NUM_COLORS; - omp_set_lock(&(writelock[i])); - count[i] += weight; - if (count[i] > maxCount) maxCount = count[i]; - omp_unset_lock(&(writelock[i])); - weight *= decay; - for (int k = 1; k < NUM_COLORS/2; ++k) { - i = (index + k) % NUM_COLORS; - omp_set_lock(&(writelock[i])); - count[i] += weight; - if (count[i] > maxCount) maxCount = count[i]; - omp_unset_lock(&(writelock[i])); - i = (index + NUM_COLORS - k) % NUM_COLORS; + int i = index % NUM_COLORS; omp_set_lock(&(writelock[i])); - count[i] += weight; - maxCount > count[i] ? true : maxCount = count[i]; - if (count[i] > maxCount) maxCount = count[i]; + count[i] += weight; + if (count[i] > maxCount) maxCount = count[i]; omp_unset_lock(&(writelock[i])); weight *= decay; - } + for (int k = 1; k < NUM_COLORS/2; ++k) { + i = (index + k) % NUM_COLORS; + omp_set_lock(&(writelock[i])); + count[i] += weight; + if (count[i] > maxCount) maxCount = count[i]; + omp_unset_lock(&(writelock[i])); + i = (index + NUM_COLORS - k) % NUM_COLORS; + omp_set_lock(&(writelock[i])); + count[i] += weight; + maxCount > count[i] ? true : maxCount = count[i]; + if (count[i] > maxCount) maxCount = count[i]; + omp_unset_lock(&(writelock[i])); + weight *= decay; + } } /*! @@ -107,25 +114,25 @@ void Spectrogram::updateLocked(int index, float weight, float decay) { * \param decay Falloff for weight upon adjacent values. */ void Spectrogram::updateCritical(int index, float weight, float decay) { - int i = index % NUM_COLORS; - #pragma omp critical - { - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - weight *= decay; - for (int k = 1; k < NUM_COLORS/2; ++k) { - i = (index + k) % NUM_COLORS; - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - i = (index + NUM_COLORS - k) % NUM_COLORS; - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - weight *= decay; + int i = index % NUM_COLORS; + #pragma omp critical + { + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + weight *= decay; + for (int k = 1; k < NUM_COLORS/2; ++k) { + i = (index + k) % NUM_COLORS; + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + i = (index + NUM_COLORS - k) % NUM_COLORS; + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + weight *= decay; + } } - } } /*! @@ -135,40 +142,41 @@ void Spectrogram::updateCritical(int index, float weight, float decay) { * \param ratio The scaling of the visualizer. Accepts values between 0.0f and 1.0f. */ void Spectrogram::draw(float ratio) { - if (maxCount > 0) { - const float DELTA = (2*PI)/NUM_COLORS; - float localmax = maxCount; - float invcount = 1.0f/localmax; - float mult = ratio*myHeight*sqrt(invcount); - switch (myDrawMode) { - case RADIAL: - for (int k = 0; k < MAX_COLOR; ++k) { - float kroot = mult*sqrt(count[k]); - xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; - yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; - col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); - } - xx[NUM_COLORS] = xx[1]; - yy[NUM_COLORS] = yy[1]; - col[NUM_COLORS] = col[1]; - can->drawConvexPolygon(NUM_COLORS+1,maxx,maxy,black,true); - can->drawConvexPolygon(NUM_COLORS+1,xx,yy,col,true); - break; - case HORIZONTAL: - can->pauseDrawing(); - for (int k = 0; k < MAX_COLOR; ++k) - can->drawLine(0,k,(ratio*myWidth*count[k])/localmax,k,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); - can->resumeDrawing(); - break; - case VERTICAL: - can->pauseDrawing(); - // can->clear(); - for (int k = 0; k < MAX_COLOR; ++k) - can->drawLine(k,myHeight,k,myHeight-(ratio*myHeight*count[k])/localmax,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); - can->resumeDrawing(); - break; + if (maxCount > 0) { + Background * bg = can->getBackground(); + const float DELTA = (2*PI)/NUM_COLORS; + float localmax = maxCount; + float invcount = 1.0f/localmax; + float mult = ratio*myHeight*sqrt(invcount); + switch (myDrawMode) { + case RADIAL: + for (int k = 0; k < MAX_COLOR; ++k) { + float kroot = mult*sqrt(count[k]); + xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; + yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; + col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); + } + xx[NUM_COLORS] = xx[1]; + yy[NUM_COLORS] = yy[1]; + col[NUM_COLORS] = col[1]; + bg->drawConvexPolygon(centerX,centerY,0, NUM_COLORS+1,maxx,maxy,0,0,0,black); + bg->drawConvexPolygon(centerX,centerY,0, NUM_COLORS+1,xx,yy,0,0,0,col); + break; + case HORIZONTAL: + can->pauseDrawing(); + for (int k = 0; k < MAX_COLOR; ++k) + bg->drawLine(-can->getWindowWidth()/2,k - can->getWindowHeight()/2,0,(ratio*myWidth*count[k])/localmax - can->getWindowWidth()/2,k - can->getWindowHeight()/2,0, 0,0,0, ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); + can->resumeDrawing(); + break; + case VERTICAL: + can->pauseDrawing(); + // can->clear(); + for (int k = 0; k < MAX_COLOR; ++k) + bg->drawLine(k-can->getWindowWidth()/2,myHeight - can->getWindowHeight()/2,0,k - can->getWindowWidth()/2,myHeight-(ratio*myHeight*count[k])/localmax - can->getWindowHeight()/2,0, 0,0,0, ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); + can->resumeDrawing(); + break; + } } - } } /*! @@ -177,7 +185,7 @@ void Spectrogram::draw(float ratio) { * down its Canvas. */ void Spectrogram::finish() { - can->wait(); + can->wait(); } } diff --git a/src/TSGL/Spectrogram.h b/src/TSGL/Spectrogram.h index e06fc63ba..fbb9a84ce 100644 --- a/src/TSGL/Spectrogram.h +++ b/src/TSGL/Spectrogram.h @@ -31,8 +31,9 @@ class Spectrogram { omp_lock_t writelock[NUM_COLORS], masterlock; int myHeight, myWidth; + float centerX, centerY; float maxCount; - int xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; + float xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; float count[NUM_COLORS+1]; ColorFloat col[NUM_COLORS+1], black[NUM_COLORS+1]; SpectrogramDrawmode myDrawMode; diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp new file mode 100644 index 000000000..1ee8a9c71 --- /dev/null +++ b/src/TSGL/Sphere.cpp @@ -0,0 +1,249 @@ +#include "Sphere.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Sphere. + * \details Explicit constructor for a Sphere object. + * \param x The x coordinate of the center of the Sphere. + * \param y The y coordinate of the center of the Sphere. + * \param z The z coordinate of the center of the Sphere. + * \param radius The Sphere's radius + * \param yaw The Sphere's yaw. + * \param pitch The Sphere's pitch. + * \param roll The Sphere's roll. + * \param c A ColorFloat for the Sphere's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Sphere with a buffer for storing the specified numbered of vertices. + */ +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { + // FIXME alpha param works kinda weirdly + if (radius <= 0) { + TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = radius; + verticalSections = 36; + horizontalSections = 20; + geometryType = GL_TRIANGLE_STRIP; + numberOfVertices = verticalSections*horizontalSections*2 + 1; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = verticalSections*horizontalSections*4 + 1; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + isOutlined = false; + attribMutex.unlock(); + for(float b=0;b &colorVec) { + attribMutex.lock(); + for(int b=0;b &colorVec); +}; + +} + +#endif /* SPHERE_H_ */ \ No newline at end of file diff --git a/src/TSGL/Square.cpp b/src/TSGL/Square.cpp index 15dfe0708..5e0837e8e 100644 --- a/src/TSGL/Square.cpp +++ b/src/TSGL/Square.cpp @@ -3,77 +3,89 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Square with monocolored fill or outline. - * \details This function draws a Square with the given upper left corner, sidelength, and color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. + * \brief Explicitly constructs a new Square with monocolored fill. + * \details This function draws a Square with the given center, sidelength, rotation, and color. + * \param x The x coordinate of the Square's center. + * \param y The y coordinate of the Square's center. + * \param z The z coordinate of the Square's center. * \param sideLength The side length of the Square in pixels. + * \param yaw The Square's yaw in 3D space. + * \param pitch The Square's pitch in 3D space. + * \param roll The Square's roll in 3D space. * \param color The color of the Square. - * \param filled Whether the Square should be filled - * (set to true by default). */ -Square::Square(float x, float y, float sideLength, const ColorFloat color, bool filled) -: Rectangle(x,y,sideLength,sideLength,color,filled) { } //Create an Rectangle with equal width and height +Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = mySideLength = sideLength; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color); + addVertex(-0.5, -0.5, 0, color); + addVertex(0.5, -0.5, 0, color); + addVertex(0.5, 0.5, 0, color); -/*! - * \brief Explicitly constructs a new Square with multicolored fill or outline. - * \details This function draws a Square with the given upper left corner, sidelength, and color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param color An array of colors for the Square's vertices. - * \param filled Whether the Square should be filled - * (set to true by default). - */ -Square::Square(float x, float y, float sideLength, const ColorFloat color[], bool filled) -: Rectangle(x,y,sideLength,sideLength,color,filled) { } //Create an Rectangle with equal width and height - -/*! - * \brief Explicitly constructs a new Square with different monocolored fill and outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor The color of the Square's fill. - * \param outlineColor The color of the Square's outline. - */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); +} /*! - * \brief Explicitly constructs a new Square with multicolored fill and monocolored outline. - * \details This function draws a square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. + * \brief Explicitly constructs a new Square with multicolored fill. + * \details This function draws a Square with the given center, sidelength, rotation, and color. + * \param x The x coordinate of the Square's center. + * \param y The y coordinate of the Square's center. + * \param z The z coordinate of the Square's center. * \param sideLength The side length of the Square in pixels. - * \param fillColor An array of colors for the Square's fill. - * \param outlineColor The color of the Square's outline. + * \param yaw The Square's yaw in 3D space. + * \param pitch The Square's pitch in 3D space. + * \param roll The Square's roll in 3D space. + * \param color An array of colors for the Square's vertices. */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height +Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = mySideLength = sideLength; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color[0]); + addVertex(-0.5, -0.5, 0, color[1]); + addVertex(0.5, -0.5, 0, color[2]); + addVertex(0.5, 0.5, 0, color[3]); + + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); +} -/*! - * \brief Explicitly constructs a new Square with monocolored fill and multicolored outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor The color of the Square's fill. - * \param outlineColor An array of colors for the Square's outline. +/** + * \brief Mutates the distance between opposite sides of the Square. + * \param sideLength The Square's new side length. */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor[]) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height +void Square::setSideLength(GLfloat sideLength) { + if (sideLength <= 0) { + TsglDebug("Cannot have a Square with sideLength less than or equal to 0."); + return; + } + attribMutex.lock(); + mySideLength = sideLength; + myXScale = myYScale = sideLength; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Square with different multicolored fill and outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor An array of colors for the Square's fill. - * \param outlineColor An array of colors for the Square's outline. +/** + * \brief Mutates the distance between opposite sides of the Square by the parameter amount. + * \param delta The amount by which to change the side length of the Square. */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor[]) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height - +void Square::changeSideLengthBy(GLfloat delta) { + if (mySideLength + delta <= 0) { + TsglDebug("Cannot have a Square with sideLength less than or equal to 0."); + return; + } + attribMutex.lock(); + mySideLength += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); +} } \ No newline at end of file diff --git a/src/TSGL/Square.h b/src/TSGL/Square.h index e0f2bf9cb..4cb093abc 100644 --- a/src/TSGL/Square.h +++ b/src/TSGL/Square.h @@ -1,31 +1,35 @@ /* -* Square.h extends Rectangle and provides a class for drawing a square to a Canvas. +* Square.h extends ConvexPolygon and provides a class for drawing a square to a Canvas. */ #ifndef SQUARE_H_ #define SQUARE_H_ -#include "Rectangle.h" // For extending our Rectangle object +#include "ConvexPolygon.h" // For extending our Rectangle object namespace tsgl { - /*! \class Square - * \brief Draw a square. - * \details Square is a class for holding Shape data for a square. - */ - class Square : public Rectangle { - public: - Square(float x, float y, float sideLength, const ColorFloat color, bool filled = true); - - Square(float x, float y, float sideLength, const ColorFloat color[], bool filled = true); - - Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor); - - Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor); - - Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor[]); +/*! \class Square +* \brief Draw a square. +* \details Square is a class for holding Shape data for a square. +*/ +class Square : public ConvexPolygon { +protected: + GLfloat mySideLength; +public: + Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color); + + Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color[]); + + /*! + * \brief Accessor for the side length of the Square. + * \details Returns the value of the mySideLength private variable, a GLfloat. + */ + GLfloat getSideLength() { return mySideLength; } + + void setSideLength(GLfloat sideLength); + + void changeSideLengthBy(GLfloat delta); }; diff --git a/src/TSGL/Star.cpp b/src/TSGL/Star.cpp index 6af22e788..8de95231f 100644 --- a/src/TSGL/Star.cpp +++ b/src/TSGL/Star.cpp @@ -3,166 +3,112 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Star with monocolored fill or outline. + * \brief Explicitly constructs a new Star with monocolored fill. * \details This function draws a star with the given center, - * radius, points, and color. + * radius, points, rotation, and color. * \param x The x coordinate of the star's center. * \param y The y coordinate of the star's center. + * \param z The z coordinate of the star's center. * \param radius The radius of the star in pixels. + * \param yaw The star's yaw in 3D space. + * \param pitch The star's pitch in 3D space. + * \param roll The star's roll in 3D space. * \param points The number of points to use in the star. * \param color The color of the star. - * \param filled Whether the star should be filled - * (set to true by default). * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float radius, int points, ColorFloat color, bool filled, bool ninja) : ConcavePolygon(points*2, filled, !filled) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), color); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), color); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), color); - } +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + //TODO: maybe take "ninja" out, decide how we want the stars to be + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = 1; + myPoints = points; + attribMutex.unlock(); + float delta = 2.0f / points * PI; + for(int i = 0; i < points; ++i) { + addVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, color); + addOutlineVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, GRAY); + if( ninja ) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } else { + addVertex(cos((i+0.5)*delta), sin((i+0.5)*delta), 0, color); + addOutlineVertex(cos((i+0.5)*delta), sin((i+0.5)*delta), 0, GRAY); + } + } } /*! - * \brief Explicitly constructs a new Star with multicolored fill or outline. + * \brief Explicitly constructs a new Star with multicolored fill. * \details This function draws a star with the given center, - * radius, points, and color. + * radius, points, rotation, and color. * \param x The x coordinate of the star's center. * \param y The y coordinate of the star's center. + * \param z The z coordinate of the star's center. * \param radius The radius of the star in pixels. + * \param yaw The star's yaw in 3D space. + * \param pitch The star's pitch in 3D space. + * \param roll The star's roll in 3D space. * \param points The number of points to use in the star. * \param color An array of colors for the star. - * \param filled Whether the star should be filled - * (set to true by default). * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float radius, int points, ColorFloat color[], bool filled, bool ninja) : ConcavePolygon(points*2, filled, !filled) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), color[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), color[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), color[i]); - } +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + //TODO: maybe take "ninja" out, decide how we want the stars to be + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = 1; + myPoints = points; + attribMutex.unlock(); + float delta = 2.0f / points * PI; + for(int i = 0; i < points; ++i) { + addVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, color[i]); + addOutlineVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, GRAY); + if( ninja ) { + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); + } else { + addVertex(cos(((float)i+0.5)*delta), sin(((float)i+0.5)*delta), 0, color[i]); + addOutlineVertex(cos(((float)i+0.5)*delta), sin(((float)i+0.5)*delta), 0, GRAY); + } + } } - /*! - * \brief Explicitly constructs a new Star with different monocolored fill and outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor The color of the star's fill. - * \param outlineColor The color of the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor, outlineColor); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor, outlineColor); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new Star with multicolored fill and monocolored outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor An array of colors for the star's fill. - * \param outlineColor The color of the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor[i], outlineColor); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor[i], outlineColor); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor[i], outlineColor); - } +void Star::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = radius; + myYScale = radius; + myRadius = radius; + attribMutex.unlock(); } - /*! - * \brief Explicitly constructs a new Star with monocolored fill and multicolored outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor The color of the star's fill. - * \param outlineColor An array of colors for the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor, outlineColor[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor, outlineColor[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor, outlineColor[i]); - } -} - - /*! - * \brief Explicitly constructs a new Star with different multicolored fill and outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor An array of colors for the star's fill. - * \param outlineColor An array of colors for the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor[i], outlineColor[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor[i], outlineColor[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor[i], outlineColor[i]); - } +void Star::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale += delta; + myYScale += delta; + myRadius += delta; + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/Star.h b/src/TSGL/Star.h index f62b6e701..1901b73d2 100644 --- a/src/TSGL/Star.h +++ b/src/TSGL/Star.h @@ -15,21 +15,18 @@ namespace tsgl { */ class Star : public ConcavePolygon { private: - float myRadius; - int myPoints; + GLfloat myRadius; + int myPoints; public: - Star(float x, float y, float radius, int points, ColorFloat color, bool filled = true, bool ninja = false); + Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja = false); - Star(float x, float y, float radius, int points, ColorFloat color[], bool filled = true, bool ninja = false); + Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja = false); - Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false); + void setRadius(GLfloat radius); - Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false); - - Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false); - - Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false); + void changeRadiusBy(GLfloat delta); + GLfloat getRadius() { return myRadius; } }; } diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 8784d1dea..d2fd5ffdd 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -6,205 +6,195 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Text instance. * \details This is the constructor for the Text class. + * \param x The center x coordinate of the text. + * \param y The center y coordinate of the text. + * \param z The center z coordinate of the text. * \param text The string to draw. - * \param loader A reference pointer to the TextureHandler with which to load the font. - * \param x The x coordinate. - * \param y The y coordinate. - * \param fontsize The size of the text in pixels. + * \param fontFilename The path of the filename detailing the font the Text will use. + * \param size The height of the text (will be relative to Canvas). + * \param yaw The yaw of the Text in 3D space. + * \param pitch The pitch of the Text in 3D space. + * \param roll The roll of the Text in 3D space. * \param color A reference to the ColorFloat to use. * \return A new Text instance with the specified string, position, and color. */ -Text::Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color) { - isTextured = true; // Let the Canvas know we're a textured object +Text::Text(float x, float y, float z, std::wstring text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color) + : Drawable(x,y,z,yaw,pitch,roll) { + shaderType = TEXT_SHADER_TYPE; myString = text; - myLoader = new TextureHandler(); - myX = x; - myY = y; - myFontSize = fontsize; + myFont = fontFilename; + mySize = size; myColor = color; - myRotation = 0; - myCenterX = 0; - myCenterY = 0; - vertices = new float[32]; // Allocate the vertices - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); + myAlpha = color.A; + myXScale = myYScale = myZScale = 1; - setRotationPoint(myCenterX, myCenterY); + // FreeType + // -------- + // All functions return a value different than 0 whenever an error occurred + if (FT_Init_FreeType(&ft)) + TsglErr("ERROR::FREETYPE: Could not init FreeType Library"); + + // load font as face + if (FT_New_Face(ft, fontFilename.c_str(), 0, &face)) + TsglErr("ERROR::FREETYPE: Failed to load font"); + + if(FT_Select_Charmap(face , FT_ENCODING_UNICODE)) + TsglErr("ERROR::FREETYPE: Charmap selection"); + + // set size to load glyphs as + FT_Set_Pixel_Sizes(face, 0, 100); + + populateCharacters(); + + vertices = new float[30]; // Allocate the vertices + + // z and texture coordinates never change + vertices[2] = 0; vertices[3] = vertices[4] = 0.0f; + vertices[7] = 0; vertices[8] = 0.0f; vertices[9] = 1.0f; + vertices[12] = 0; vertices[13] = vertices[14] = 1.0f; + vertices[17] = 0; vertices[18] = vertices[19] = 0.0f; + vertices[22] = 0; vertices[23] = vertices[24] = 1.0f; + vertices[27] = 0; vertices[28] = 1.0f; vertices[29] = 0.0f; + + init = true; } /*! * \brief Draw the Text. * \details This function actually draws the Text to the Canvas. + * \param shader Pointer to appropriate instance of Shader being used to render the Text. */ -void Text::draw() { - vertices[0] = myX; // Pre-init the array with the start coords - vertices[1] = myY; +void Text::draw(Shader * shader) { + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(mySize / 100, mySize / 100, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glUniform4f(glGetUniformLocation(shader->ID, "textColor"), myColor.R, myColor.G, myColor.B, myColor.A); + + float mouseX = -myWidth / 2; + float mouseY = -myHeight / 2; + const wchar_t* wideText = myString.c_str(); + // std::wstring::const_iterator c; + for (unsigned int i = 0; i < myString.size(); i++) { + Character ch = Characters[wideText[i]]; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + GLuint texture; + glGenTextures(1, &texture); + // create and render a new texture based off the data in Characters + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + ch.Bitmap.width, + ch.Bitmap.rows, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + ch.Bitmap.buffer + ); + + 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); + + // update vertices for each character + float xpos = mouseX + ch.Bearing.x; + float ypos = mouseY - ( (float) ch.Bitmap.rows - ch.Bearing.y); + + float w = ch.Bitmap.width; + float h = ch.Bitmap.rows; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = myColor.R; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = myColor.G; // (Default to opaque white) - vertices[4] = vertices[12] = vertices[20] = vertices[28] = myColor.B; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = myColor.A; + //triangle 1 + vertices[0] = xpos; vertices[1] = ypos + h; + vertices[5] = xpos; vertices[6] = ypos; + vertices[10] = xpos + w; vertices[11] = ypos; + //triangle 2 + vertices[15] = xpos; vertices[16] = ypos + h; + vertices[20] = xpos + w; vertices[21] = ypos; + vertices[25] = xpos + w; vertices[26] = ypos + h; - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left - vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right + // actually draw stuff + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); - myLoader->drawText(myString, myFontSize, vertices, myCenterX, myCenterY, myRotation); + glDeleteTextures(1, &texture); + + // now advance cursors for next glyph (note that advance is number of 1/64 pixels) + mouseX += (ch.Advance >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) + } } /*! * \brief Alter the Text's string * \details This function changes myString to the parameter text * \param text The text to change myString to. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \warning The center of the text will not change despite any differences in rendered string length. */ void Text::setText(std::wstring text) { - myString = text; - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); + attribMutex.lock(); + init = false; + std::wstring::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } + myString = text; + populateCharacters(); + init = true; + attribMutex.unlock(); } /*! * \brief Alter the Text's font size - * \details This function changes myFontSize to the parameter fontsize. - * \param fontsize The new fontsize. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \details This function changes mySize to the parameter size. + * \param size The new size. + * \warning The center of the text will not change despite any differences in rendered string length. */ -void Text::setFontSize(int fontsize) { - myFontSize = fontsize; - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); - } +void Text::setSize(float size) { + attribMutex.lock(); + mySize = size; + attribMutex.unlock(); } /*! * \brief Alter the Text's font * \details This function changes myLoader's font to the parameter font. * \param filename The new font file name. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \warning The center of the text will not change despite any differences in rendered string length. */ void Text::setFont(std::string filename) { - myLoader->loadFont(filename); - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); - } -} - -/*! - * \brief Alter the Text's lower left hand corner location - * \details This function changes myX and myY to the parameter x and y. - * \param x The new x-coordinate for myX. - * \param y The new y-coordinate for myY. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setBottomLeftCorner(float x, float y) { - float deltaX = x - myX; - float deltaY = y - myY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; + attribMutex.lock(); + init = false; + std::wstring::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } - myCenterX += deltaX; - myCenterY += deltaY; - myX = x; - myY = y; -} + FT_Done_Face(face); + myFont = filename; + // load font as face -/*! - * \brief Alter the Text's lower left hand corner location - * \details This function changes myX and myY to the parameter x and y. - * \param x The new x-coordinate for myX. - * \param y The new y-coordinate for myY. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setCenter(float x, float y) { - float deltaX = x - myCenterX; - float deltaY = y - myCenterY; - myX += deltaX; - myY += deltaY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - setRotationPoint(x, y); - } - myCenterX = x; - myCenterY = y; -} + if (FT_New_Face(ft, myFont.c_str(), 0, &face)) + TsglErr("ERROR::FREETYPE: Failed to load font"); -/*! - * \brief Alter the Text's location by deltaX and deltaY. - * \details This function changes all coordinate variables by the parameter deltaX and deltaY - * \param deltaX The amount to change x-coordinates by. - * \param deltaY The amount to change y-coordinates by. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::moveTextBy(float deltaX, float deltaY) { - myX += deltaX; - myY += deltaY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; -} + if(FT_Select_Charmap(face , FT_ENCODING_UNICODE)) + TsglErr("ERROR::FREETYPE: Charmap selection"); -/*! - * \brief Mutator for the rotation of the Text. - * \details Rotates the Text vertices around centerX, centerY. - * \param radians Float value denoting how many radians to rotate the Text. - */ -void Text::setRotation(float radians) { - // myRotation = radians; - if(radians != myRotation) { - attribMutex.lock(); + // set size to load glyphs as + FT_Set_Pixel_Sizes(face, 0, 100); - // distance between myCenter and bottom left corner - float deltaX = std::roundf(myCenterX - myX); - float deltaY = std::roundf(myCenterY - myY); - - //deal with rotation variables - float s = sin(radians - myRotation); - float c = cos(radians - myRotation); - myRotation = radians; - - //rotate myCenter around myRotationPoint - float x = myCenterX; - float y = myCenterY; - x -= myRotationPointX; - y -= myRotationPointY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - x = xnew + myRotationPointX; - y = ynew + myRotationPointY; - myCenterX = x; - myCenterY = y; - - //calculate new location of bottom left corner - myX = myCenterX - deltaX; - myY = myCenterY - deltaY; + populateCharacters(); + init = true; attribMutex.unlock(); - } } /*! @@ -213,12 +203,68 @@ void Text::setRotation(float radians) { * \param color The ColorFloat to change myColor to. */ void Text::setColor(const ColorFloat& color) { + attribMutex.lock(); myColor = color; + myAlpha = color.A; + attribMutex.unlock(); +} + +/*! + * \brief Private helper method for populating Characters with characters based on myString + * \details This function assigns values to myWidth and myHeight based on + * the glyphs loaded based on myFont and myString. + */ +void Text::populateCharacters() { + const wchar_t* wideChar = myString.c_str(); + Characters.clear(); // note: this will leak memory if you don't free the bitmaps within first. see most mutators. + myWidth = 0; + myHeight = 0; + + FT_Bitmap * ftbmps = new FT_Bitmap[myString.size()]; + + FT_GlyphSlot glyph = face->glyph; + FT_UInt index; + + for (unsigned int i = 0; i < myString.size(); i++) { + // Load character glyph + index = FT_Get_Char_Index(face, wideChar[i]); + if (FT_Load_Glyph(face, index, FT_LOAD_RENDER)) + { + TsglErr("ERROR::FREETYTPE: Failed to load Glyph"); + continue; + } + + FT_Bitmap_Init(&ftbmps[i]); + + if (FT_Bitmap_Copy(ft, &glyph->bitmap, &ftbmps[i])) { + TsglErr("ERROR::FREETYTPE: Failed to copy Bitmap"); + continue; + } + + Character character = { + ftbmps[i], + glm::ivec2(glyph->bitmap_left, glyph->bitmap_top), + glyph->advance.x + }; + + Characters.insert(std::pair(wideChar[i], character)); + + myWidth += glyph->advance.x >> 6; + if (glyph->bitmap.rows > myHeight) + myHeight = glyph->bitmap.rows; + } + + delete [] ftbmps; } Text::~Text() { - delete myLoader; - delete[] vertices; + // destroy FreeType once we're finished + std::wstring::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); + } + FT_Done_Face(face); + FT_Done_FreeType(ft); } diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index 230f4865b..703c289c8 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -1,12 +1,16 @@ /* - * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. + * Text.h extends Drawable and provides a class for drawing a string of text to the Canvas. */ #ifndef TEXT_H_ #define TEXT_H_ #include "Drawable.h" // For extending our Shape object -#include "TextureHandler.h" +#include +#include +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H namespace tsgl { @@ -18,33 +22,47 @@ namespace tsgl { */ class Text : public Drawable { private: - ColorFloat myColor; - unsigned int myFontSize; - TextureHandler* myLoader; - float * vertices; std::wstring myString; - float myX, myY; - float myRotation; + float mySize; + std::string myFont; + ColorFloat myColor; + + GLfloat myWidth; + GLfloat myHeight; + + FT_Face face; + FT_Library ft; + + struct Character { + FT_Bitmap Bitmap; + glm::ivec2 Bearing; // Offset from baseline to left/top of glyph + unsigned int Advance; // Horizontal offset to advance to next glyph + }; + + std::map Characters; + + void populateCharacters(); public: - Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color); + Text(float x, float y, float z, std::wstring text, std::string fontFilename, float size, float yaw, float pitch, float roll, const ColorFloat &color); - virtual void draw(); + virtual void draw(Shader * shader); virtual void setText(std::wstring text); - virtual void setFontSize(int fontsize); + virtual void setSize(float size); virtual void setFont(std::string filename); - virtual void setBottomLeftCorner(float x, float y); + virtual void setColor(const ColorFloat& color); - virtual void setCenter(float x, float y); + std::wstring getText() { return myString; } - virtual void moveTextBy(float deltaX, float deltaY); + float getSize() { return mySize; } - virtual void setRotation(float radians); + GLfloat getWidth() { return myWidth; } + GLfloat getHeight() { return myHeight; } - virtual void setColor(const ColorFloat& color); + ColorFloat getColor() { return myColor; } ~Text(); }; diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index 026de96be..202b494a5 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -1,795 +1,815 @@ -#include "TextureHandler.h" - -namespace tsgl { - - //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) - #ifndef STB_DEFINE - #define STB_IMAGE_WRITE_IMPLEMENTATION - #include "stb/stb_image_write.h" - #define STB_IMAGE_IMPLEMENTATION - #include "stb/stb_image.h" - #define STB_DEFINE -//It may look truly awful....but its an easy way to turn off warnings -//solely for stb.h. Sorry :'( -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-fpermissive" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wwrite-strings" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-result" - #include "stb/stb.h" -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop - #endif - - //List of default fonts to check for -#ifndef DEFAULTFONTS -#define DEFAULTFONTS -#ifdef _WIN32 - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "C:\\Windows\\Fonts\\ARIALUNI.ttf", - "C:\\Windows\\Fonts\\ARIAL.ttf", - "C:\\Windows\\Fonts\\COUR.ttf", - "C:\\Windows\\Fonts\\COURI.ttf" - }; -#endif -#ifdef __APPLE__ - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "/Library/Fonts/Arial.ttf", - "/Library/Fonts/Courier New.ttf", - "/Library/Fonts/Georgia.ttf", - "/opt/X11/share/fonts/TTF/VeraSe.ttf", - }; -#endif -#ifdef __linux__ - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "/usr/share/fonts/dejavu/DejaVuSerif.ttf", - "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", - "/usr/share/fonts/TTF/DejaVuSerif.ttf", - "/usr/share/fonts/TTF/arial.ttf", - "/usr/share/fonts/TTF/cour.ttf", - "/usr/share/fonts/TTF/couri.ttf" - }; -#endif -#endif - -#define GL_GLEXT_PROTOTYPES - -/*! - * \brief Default TextureHandler constructor method. - * \details This is the default constructor for theTextureHandler Canvas class. - * \return A new TextureHandler instance. - */ -TextureHandler::TextureHandler() { - fontLibrary = nullptr; - fontFace = nullptr; -} - -/*! - * \brief TextureHandler destructor method. - * \details This is the destructor for the TextureHandler class. - * \details Frees up memory that was allocated to a TextureHandler instance. - */ -TextureHandler::~TextureHandler() { - for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { - glDeleteTextures(1, &(it->second)); - } - - for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { - FT_Done_Face(it->second); - } - FT_Done_FreeType(fontLibrary); -} - -void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, - const unsigned int &width, const unsigned int &height, - int glMode) { - // Generate the OpenGL texture object - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - if (glMode == GL_ALPHA) { - unsigned char* newBuffer = new unsigned char[width * height * 4]; - unsigned maxSize = width * height; - for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { - newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); - delete[] newBuffer; - } else { - if (glMode == GL_RED) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -} - -void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { - // Generate the OpenGL texture object - GLtexture texture; - - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - if (glMode == GL_ALPHA) { - unsigned char* newBuffer = new unsigned char[width * height * 4]; - unsigned maxSize = width * height; - for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { - newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); - delete[] newBuffer; - } else { - if (glMode == GL_RED) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - float* vertices = new float[32]; - vertices[0] = x; - vertices[1] = y + height; - vertices[8] = x + width; - vertices[9] = y + height; - vertices[16] = x + width; - vertices[17] = y; - vertices[24] = x; - vertices[25] = y; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; - vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left - vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right - - // 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_NEAREST); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDeleteTextures(1, &texture); - - delete[] vertices; -} - -/*! - * \brief Draws text. - * \details Draws the text specified by its parameters onto a Canvas. - * \param text The UTF-8 encoded string of text to be drawn. - * \param font_size The size of the text in pixels. - * \param vertices An array of vertex data for the bonding box of the text. - * \note vertices will be partially automatically set by drawText() - * itself in order to draw / kern the text properly, but the color, starting - * position, and texture coordinates will be left unchanged. - * \note If no font is loaded before calling this function, TSGL will attempt to locate a - * default font at ../assets/freefont/FreeMono.ttf. - * \return True if successful, false otherwise. - * \bug If the default font cannot be located, TSGL will crash. - */ -bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { - const wchar_t* string = text.c_str(); - if(fontFace == nullptr) { //If no font is set, load up a default one - bool found = false; - for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { - if (fileExists(DEFAULTFONTPATHS[i])) { - TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW - loadFont(DEFAULTFONTPATHS[i]); - found = true; - break; - } - } - if (!found) { - TsglErr("No suitable fonts found...exiting"); //NEW - exit(44); - } - } - - FT_GlyphSlot glyph = fontFace->glyph; - FT_UInt current_glyph_index, previous_glyph_index = 0; - int penX = vertices[0], - penY = vertices[1]; - - bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); - if (error) { - fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); - return false; - } - - bool use_kerning = FT_HAS_KERNING(fontFace); - - for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - - if (use_kerning && previous_glyph_index && current_glyph_index) { - FT_Vector delta; - FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); - penX += delta.x >> 6; - penY += delta.y >> 6; - } - - error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "FT_Load_Char failed\n"); - return false; - } - - previous_glyph_index = current_glyph_index; - - int glMode = GL_ALPHA; - - char fontMode = glyph->bitmap.pixel_mode; - if (fontMode == FT_PIXEL_MODE_MONO) - glMode = GL_RED; - else if (fontMode == FT_PIXEL_MODE_GRAY) - glMode = GL_ALPHA; - else if (fontMode == FT_PIXEL_MODE_LCD) - glMode = GL_RGB; - else if (fontMode == FT_PIXEL_MODE_LCD_V) - glMode = GL_RGB; -#ifndef _WIN32 - else if (fontMode == FT_PIXEL_MODE_BGRA) - glMode = GL_RGBA; -#endif - - GLtexture texture; - createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); - glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture - 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); - - vertices[0] = vertices[16] = penX + glyph->bitmap_left; - vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; - vertices[1] = vertices[9] = penY - glyph->bitmap_top; - vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; - - - float s = sin(rotation); - float c = cos(rotation); - for(int i = 0; i < 4; i++) { - float x = vertices[8*i]; - float y = vertices[8*i+1]; - x -= centerX; - y -= centerY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + centerX; - y = ynew + centerY; - vertices[8*i] = x; - vertices[8*i+1] = y; - } - - penX += glyph->advance.x >> 6; - penY += glyph->advance.y >> 6; - - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character - - glDeleteTextures(1, &texture); - } - return true; -} - -/*! - * \brief Loads a font. - * \details Loads a font from the library given by filename. - * \param filename The file name of the font to be loaded. - * \warning If the font cannot be found then an error message is printed out. - * \warning If the font library is not correctly installed then an error message is printed out. - * \warning If the font is not supported then an error message is printed out. - * \return True if successful, false otherwise. - */ -bool TextureHandler::loadFont(const std::string& filename) { - if (fontLibrary == nullptr) { - if (FT_Init_FreeType(&fontLibrary)) { - fprintf(stderr, "An error occurred during freetype font library initialization\n"); - return false; - } - } - - if(filename == "") { - fontFace = nullptr; - return true; - } - - if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already - FT_Face tmp_face; - int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); - if (error == FT_Err_Unknown_File_Format) { - fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" - "font format is unsupported\n", filename.c_str()); - return false; - } else if (error) { - fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); - return false; - } - - loadedFonts[filename] = tmp_face; - fontFace = tmp_face; - FT_Select_Charmap(fontFace , ft_encoding_unicode); - } else { - fontFace = loadedFonts[filename]; - } - - return true; -} - -void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { - const wchar_t* string = text.c_str(); - if(fontFace == nullptr) { //If no font is set, load up a default one - bool found = false; - for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { - if (fileExists(DEFAULTFONTPATHS[i])) { - TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW - loadFont(DEFAULTFONTPATHS[i]); - found = true; - break; - } - } - if (!found) { - TsglErr("No suitable fonts found...exiting"); //NEW - exit(44); - } - } - FT_GlyphSlot glyph = fontFace->glyph; - FT_UInt current_glyph_index, previous_glyph_index = 0; - int penX = leftX; - int penY = bottomY; - - int minX = leftX; - int minY = bottomY; - int maxX = leftX; - int maxY = bottomY; - - int currentRightX, currentTopY, currentBottomY; - - bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); - if (error) { - fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); - return; - } - - bool use_kerning = FT_HAS_KERNING(fontFace); - - for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - - if (use_kerning && previous_glyph_index && current_glyph_index) { - FT_Vector delta; - FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); - penX += delta.x >> 6; - penY += delta.y >> 6; - } - - error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "FT_Load_Char falied\n"); - return; - } - - previous_glyph_index = current_glyph_index; - - currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; - currentTopY = penY - glyph->bitmap_top; - currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; - - maxX = currentRightX; - if(currentBottomY > maxY) { - maxY = currentBottomY; - } - if(currentTopY < minY) { - minY = currentTopY; - } - - penX += glyph->advance.x >> 6; - penY += glyph->advance.y >> 6; - } - - centerX = (minX + maxX) / 2; - centerY = (minY + maxY) / 2; -} - -/*! - * \brief Loads an image. - * \details Loads a .png, .jpeg, or .bmp image from a file. - * \param filename The file name of the picture. - * \param width A reference variable for holding the width of the picture. - * \param height A reference variable for holding the height of the picture. - * \param texture A reference variable for holding the texture of the picture. - * (same as return value) - * \return The texture that created from the loaded image. - */ -GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { - if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already - texture = 0; - std::string extension = filename.substr(filename.find_last_of('.')); - if (extension == ".png") - loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); - else if (extension == ".jpg" || extension == ".jpeg") - loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); - else if (extension == ".bmp") - loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); - else { - fprintf(stderr, "File extension not found\n"); - return 0; - } - } else { - texture = loadedTextures[filename]; - } - - return texture; -} - -GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself - - // Data read from the header of the BMP file - unsigned char header[54]; // Each BMP file begins by a 54-bytes header - unsigned int imageSize; // = width*height*3 - // Actual RGB data - unsigned char * data; - - // Open the file -#ifdef _WIN32 - FILE* file; - fopen_s(&file, filename, "rb"); -#else - FILE* file = fopen(filename, "rb"); -#endif - - if (!file) { - fprintf(stderr, "Can't open %s: no such file\n", filename); - return 0; - } - - if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem - fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); - fclose(file); - return 0; - } - - if (header[0] != 'B' || header[1] != 'M') { - fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); - fclose(file); - return 0; - } - - imageSize = width = height = 0; - // Get info out of header as 4 byte unsigned ints - for (int i = 3; i >= 0; i--) - imageSize = (imageSize << 8) | header[0x22 + i]; - for (int i = 3; i >= 0; i--) - width = (width << 8) | header[0x12 + i]; - for (int i = 3; i >= 0; i--) - height = (height << 8) | header[0x16 + i]; - - int components = imageSize / width / height; - - // Some BMP files are misformatted, guess missing information - if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component - - // Create a buffer - data = new unsigned char[imageSize]; - - // Read the actual data from the file into the buffer - if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem - fprintf(stderr, "%s: file ended unexpectedly\n", filename); - fclose(file); - return 0; - } - - //Everything is in memory now, the file can be closed - fclose(file); - - char tmp; - //Reverse the endian-ness of the colors - if (components == 4) { - for (unsigned int i = 0; i < imageSize; i += 4) { - tmp = data[i]; - data[i] = data[i + 3]; - data[i + 3] = tmp; - tmp = data[i + 1]; - data[i + 1] = data[i + 2]; - data[i + 2] = tmp; - } - } else if (components == 3) { - for (unsigned int i = 0; i < imageSize; i += 3) { - tmp = data[i]; - data[i] = data[i + 1]; - data[i + 1] = tmp; - } - } - - // Flip the image vertically, since BMPs are loaded bottom to top - for (unsigned int j = 0; j < height - (height / 2); j++) { - for (unsigned int i = 0; i < components * width; i++) { - int s1 = components * width * j + i; - int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j - tmp = data[s1]; - data[s1] = data[s2]; - data[s2] = tmp; - } - } - - if (components == 3) - components = GL_RGB; - else if (components == 4) - components = GL_RGBA; - - createGLtextureFromBuffer(texture, data, width, height, components); - - delete[] data; - - return texture; -} - -/*! - * \brief Gets the dimensions of an image - * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. - * \param filename The file name of the picture. - * \param width A reference variable for holding the width of the picture. - * \param height A reference variable for holding the height of the picture. - * \return The texture that created from the loaded image. - */ -void TextureHandler::getDimensions(std::string filename, int &width, int &height) { - int w = 0, h = 0; - stbi_info(filename.c_str(), &w, &h, 0); - width = w; height = h; -} - -GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - unsigned char *data; - int w = 0, h = 0; - TsglDebug(std::string("Loading ") + filename); - data = stbi_load(filename, &w, &h, 0, 4); - assert(data); - if (!data) { - TsglErr(std::string("Loading ") + filename + " failed"); - return texture; - } - TsglDebug(std::string("Loading ") + filename + " succeeded"); - TsglDebug(to_string(w) + "," + to_string(h)); - createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); - width = w, height = h; - free(data); - return texture; -} - -GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - unsigned char *data; - int w = 0, h = 0; - TsglDebug(std::string("Loading ") + filename); - data = stbi_load(filename, &w, &h, 0, 4); - assert(data); - if (!data) { - TsglErr(std::string("Loading ") + filename + " failed"); - return texture; - } - TsglDebug(std::string("Loading ") + filename + " succeeded"); - TsglDebug(to_string(w) + "," + to_string(h)); - createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); - width = w, height = h; - free(data); - return texture; -} - -/*! - * \brief Saves an Image. - * \details Saves an Image to file that was captured from a Canvas object. - * \param filename The name of the file to save the Image to. - * \param pixels The pixel data for the Image. - * \param width The width of the Image. - * \param height The height of the Image. - * \return True if successful, false otherwise. - */ -bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, - unsigned int width, unsigned int height) const { - std::string extension = filename.substr(filename.find_last_of('.')); - bool success = false; - if (extension == ".png") - success = saveToPNG(filename.c_str(), pixels, width, height); - else if (extension == ".jpg" || extension == ".jpeg") - fprintf(stderr, "JPG saving not implemented yet\n"); - else if (extension == ".bmp") - success = saveToBMP(filename.c_str(), pixels, width, height); - else - fprintf(stderr, "File extension not found\n"); - return success; -} - -bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { - unsigned char header[54]; // Each BMP file begins by a 54-bytes header - unsigned int imageSize = w * h * 3; // Byte-size of the data for the image - unsigned int totalSize = imageSize + 54; - - // Open the file -#ifdef _WIN32 - FILE* file; - fopen_s(&file, filename, "wb"); -#else - FILE* file = fopen(filename, "wb"); -#endif - - if (!file) { - fprintf(stderr, "Can't open %s: no such file\n", filename); - return false; - } - - unsigned char padding = 4 - (w * 3) % 4; - if (padding == 4) padding = 0; - int rawdatasize = (w * 3 + padding) * h; - - header[0] = 'B'; - header[1] = 'M'; - header[2] = (unsigned char) totalSize; - header[3] = (unsigned char)(totalSize >> 8); - header[4] = (unsigned char)(totalSize >> 16); - header[5] = (unsigned char)(totalSize >> 24); - for (unsigned i = 6; i <= 9; ++i) - header[i] = 0; - header[10] = 54; - for (unsigned i = 11; i <= 13; ++i) - header[i] = 0; - header[14] = 40; - for (unsigned i = 15; i <= 17; ++i) - header[i] = 0; - header[18] = (unsigned char) w; - header[19] = (unsigned char)(w >> 8); - header[20] = (unsigned char)(w >> 16); - header[21] = (unsigned char)(w >> 24); - header[22] = (unsigned char) h; - header[23] = (unsigned char)(h >> 8); - header[24] = (unsigned char)(h >> 16); - header[25] = (unsigned char)(h >> 24); - header[26] = 1; - header[27] = 0; - header[28] = 24; - header[29] = 0; - for (unsigned i = 30; i <= 33; ++i) - header[i] = 0; - header[34] = (unsigned char) rawdatasize; - header[35] = (unsigned char)(rawdatasize >> 8); - header[36] = (unsigned char)(rawdatasize >> 16); - header[37] = (unsigned char)(rawdatasize >> 24); - header[38] = 19; - header[39] = 11; - header[40] = 0; - header[41] = 0; - header[42] = 19; - header[43] = 11; - header[44] = 0; - header[45] = 0; - for (unsigned i = 46; i <= 53; ++i) - header[i] = 0; - - unsigned char *rawdata = new unsigned char[rawdatasize]; - - unsigned rawpos = 0, datapos = 0; - for (unsigned j = 0; j < h; ++j) { - for (unsigned i = 0; i < w; ++i) { - rawdata[rawpos] = pixels[datapos+2]; - rawdata[rawpos+1] = pixels[datapos+1]; - rawdata[rawpos+2] = pixels[datapos]; - rawpos += 3; - datapos += 3; - } - for (unsigned i = 0; i < padding; ++i) { - rawdata[rawpos++] = 0; - } - } - - fwrite(header, 54, 1, file); - fwrite(rawdata, 1, rawdatasize, file); - fclose(file); - - delete[] rawdata; - - return true; -} - -bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { - // Flip the image, since for some reason the library call - // flips the image upside down when it saves - for (unsigned int j = 0; j < h - (h / 2); j++) { - for (unsigned int i = 0; i < 3 * w; i++) { - int s1 = 3 * w * j + i; - int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j - char tmp = pixels[s1]; - pixels[s1] = pixels[s2]; - pixels[s2] = tmp; - } - } - stbi_write_png(filename, w, h, 3, pixels, 0); - return true; -} - -//-------------------------Unit testing--------------------------------------------- -/*! - * \brief Runs the Unit tests for TextureHandler. - */ -void TextureHandler::runTests() { - TsglDebug("Testing TextureHandler class..."); - TextureHandler tester; - tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); - TsglDebug("Unit tests for TextureHandler complete."); - std::cout << std::endl; -} - -bool TextureHandler::testLoadFont(TextureHandler& test) { - int passed = 0; //Passed tests - int failed = 0; //Failed tests - //Test 1: Loading in the font at the start - if(test.fontFace == nullptr) { - test.loadFont("../assets/freefont/FreeMono.ttf"); - if(test.fontFace != nullptr) { - passed++; - } else { - failed++; - TsglErr("Test 1, Loading font for testLoadFont() failed!"); - } - } - - if(passed == 1 && failed == 0) { - TsglDebug("Unit test for loading in fonts passed!"); - return true; - } else { - TsglErr("This many tests passed for testLoadFont: "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests failed for testLoadFont: "); - std::cout << " " << failed << std::endl; - return false; - } -} -//----------------------------End Unit testing--------------------------------------- -} +// #include "TextureHandler.h" + +// namespace tsgl { + +// //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) +// // #ifndef STB_DEFINE +// // #define STB_IMAGE_WRITE_IMPLEMENTATION +// // #include "stb/stb_image_write.h" +// // #define STB_IMAGE_IMPLEMENTATION +// // #include "stb/stb_image.h" +// // #define STB_DEFINE +// // //It may look truly awful....but its an easy way to turn off warnings +// // //solely for stb.h. Sorry :'( +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-fpermissive" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wsign-compare" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wstrict-aliasing" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wwrite-strings" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wtype-limits" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wunused-but-set-variable" +// // // #pragma GCC diagnostic push +// // // #pragma GCC diagnostic ignored "-Wunused-result" +// // // #include "stb/stb.h" +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // // #pragma GCC diagnostic pop +// // #endif + +// //List of default fonts to check for +// #ifndef DEFAULTFONTS +// #define DEFAULTFONTS +// #ifdef _WIN32 +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "C:\\Windows\\Fonts\\ARIALUNI.ttf", +// "C:\\Windows\\Fonts\\ARIAL.ttf", +// "C:\\Windows\\Fonts\\COUR.ttf", +// "C:\\Windows\\Fonts\\COURI.ttf" +// }; +// #endif +// #ifdef __CYGWIN__ +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "C:\\Windows\\Fonts\\ARIALUNI.ttf", +// "C:\\Windows\\Fonts\\ARIAL.ttf", +// "C:\\Windows\\Fonts\\COUR.ttf", +// "C:\\Windows\\Fonts\\COURI.ttf" +// }; +// #endif +// #ifdef __APPLE__ +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "/Library/Fonts/Arial.ttf", +// "/Library/Fonts/Courier New.ttf", +// "/Library/Fonts/Georgia.ttf", +// "/opt/X11/share/fonts/TTF/VeraSe.ttf", +// }; +// #endif +// #ifdef __linux__ +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "/usr/share/fonts/dejavu/DejaVuSerif.ttf", +// "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", +// "/usr/share/fonts/TTF/DejaVuSerif.ttf", +// "/usr/share/fonts/TTF/arial.ttf", +// "/usr/share/fonts/TTF/cour.ttf", +// "/usr/share/fonts/TTF/couri.ttf" +// }; +// #endif +// #endif + +// #define GL_GLEXT_PROTOTYPES + +// /*! +// * \brief Default TextureHandler constructor method. +// * \details This is the default constructor for theTextureHandler Canvas class. +// * \return A new TextureHandler instance. +// */ +// TextureHandler::TextureHandler() { +// fontLibrary = nullptr; +// fontFace = nullptr; +// } + +// /*! +// * \brief TextureHandler destructor method. +// * \details This is the destructor for the TextureHandler class. +// * \details Frees up memory that was allocated to a TextureHandler instance. +// */ +// TextureHandler::~TextureHandler() { +// for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { +// glDeleteTextures(1, &(it->second)); +// } + +// for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { +// FT_Done_Face(it->second); +// } +// FT_Done_FreeType(fontLibrary); +// } + +// void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, +// const unsigned int &width, const unsigned int &height, +// int glMode) { +// // Generate the OpenGL texture object +// glGenTextures(1, &texture); +// glBindTexture(GL_TEXTURE_2D, texture); + +// if (glMode == GL_ALPHA) { +// unsigned char* newBuffer = new unsigned char[width * height * 4]; +// unsigned maxSize = width * height; +// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { +// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; +// } + +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); +// delete[] newBuffer; +// } else { +// if (glMode == GL_RED) { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// } else { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +// } +// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); +// } + +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// } + +// void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { +// // Generate the OpenGL texture object +// GLtexture texture; + +// glGenTextures(1, &texture); +// glBindTexture(GL_TEXTURE_2D, texture); + +// if (glMode == GL_ALPHA) { +// unsigned char* newBuffer = new unsigned char[width * height * 4]; +// unsigned maxSize = width * height; +// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { +// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; +// } + +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); +// delete[] newBuffer; +// } else { +// if (glMode == GL_RED) { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// } else { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +// } +// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); +// } + +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + +// float* vertices = new float[32]; +// vertices[0] = x; +// vertices[1] = y + height; +// vertices[8] = x + width; +// vertices[9] = y + height; +// vertices[16] = x + width; +// vertices[17] = y; +// vertices[24] = x; +// vertices[25] = y; +// vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords +// vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; +// vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; +// vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; +// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left +// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right +// vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left +// vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right + +// // 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_NEAREST); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); +// glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + +// glDeleteTextures(1, &texture); + +// delete[] vertices; +// } + +// /*! +// * \brief Draws text. +// * \details Draws the text specified by its parameters onto a Canvas. +// * \param text The UTF-8 encoded string of text to be drawn. +// * \param font_size The size of the text in pixels. +// * \param vertices An array of vertex data for the bonding box of the text. +// * \note vertices will be partially automatically set by drawText() +// * itself in order to draw / kern the text properly, but the color, starting +// * position, and texture coordinates will be left unchanged. +// * \note If no font is loaded before calling this function, TSGL will attempt to locate a +// * default font at ../assets/freefont/FreeMono.ttf. +// * \return True if successful, false otherwise. +// * \bug If the default font cannot be located, TSGL will crash. +// */ +// bool TextureHandler::drawText(std::string text, unsigned int font_size, float* vertices) { +// // const wchar_t* string = text.c_str(); +// if(fontFace == nullptr) { //If no font is set, load up a default one +// bool found = false; +// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { +// if (fileExists(DEFAULTFONTPATHS[i])) { +// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW +// loadFont(DEFAULTFONTPATHS[i]); +// found = true; +// break; +// } +// } +// if (!found) { +// TsglErr("No suitable fonts found...exiting"); //NEW +// exit(44); +// } +// } + +// FT_GlyphSlot glyph = fontFace->glyph; +// FT_UInt current_glyph_index, previous_glyph_index = 0; +// int penX = vertices[0], +// penY = vertices[1]; + +// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); +// if (error) { +// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); +// return false; +// } + +// bool use_kerning = FT_HAS_KERNING(fontFace); + +// for (unsigned int i = 0; i < text.size(); i++) { +// current_glyph_index = FT_Get_Char_Index(fontFace, text[i]); + +// if (use_kerning && previous_glyph_index && current_glyph_index) { +// FT_Vector delta; +// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); +// penX += delta.x >> 6; +// penY += delta.y >> 6; +// } + +// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); +// if (error) { +// fprintf(stderr, "FT_Load_Char failed\n"); +// return false; +// } + +// previous_glyph_index = current_glyph_index; + +// int glMode = GL_ALPHA; + +// char fontMode = glyph->bitmap.pixel_mode; +// if (fontMode == FT_PIXEL_MODE_MONO) +// glMode = GL_RED; +// else if (fontMode == FT_PIXEL_MODE_GRAY) +// glMode = GL_ALPHA; +// else if (fontMode == FT_PIXEL_MODE_LCD) +// glMode = GL_RGB; +// else if (fontMode == FT_PIXEL_MODE_LCD_V) +// glMode = GL_RGB; +// #ifndef _WIN32 +// else if (fontMode == FT_PIXEL_MODE_BGRA) +// glMode = GL_RGBA; +// #endif + +// GLtexture texture; +// createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); +// glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture +// 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); + +// /* triangles: +// bottom left-bottom right-top left +// top right-top left-bottom right +// */ + +// vertices[0] = vertices[10] = vertices[20] = penX + glyph->bitmap_left; // left +// vertices[5] = vertices[16] = vertices[25] = penX + glyph->bitmap_left + glyph->bitmap.width; //right +// vertices[1] = vertices[6] = vertices[26] = penY - glyph->bitmap_top; // bottom +// vertices[15] = vertices[11] = vertices[21] = penY - glyph->bitmap_top + glyph->bitmap.rows; // top + +// penX += glyph->advance.x >> 6; +// penY += glyph->advance.y >> 6; + +// glBufferData(GL_ARRAY_BUFFER, 30 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer +// glDrawArrays(GL_TRIANGLES, 0, 6); // Draw the character + +// glDeleteTextures(1, &texture); +// } +// return true; +// } + +// /*! +// * \brief Loads a font. +// * \details Loads a font from the library given by filename. +// * \param filename The file name of the font to be loaded. +// * \warning If the font cannot be found then an error message is printed out. +// * \warning If the font library is not correctly installed then an error message is printed out. +// * \warning If the font is not supported then an error message is printed out. +// * \return True if successful, false otherwise. +// */ +// bool TextureHandler::loadFont(const std::string& filename) { +// if (fontLibrary == nullptr) { +// if (FT_Init_FreeType(&fontLibrary)) { +// fprintf(stderr, "An error occurred during freetype font library initialization\n"); +// return false; +// } +// } + +// if(filename == "") { +// fontFace = nullptr; +// return true; +// } + +// if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already +// FT_Face tmp_face; +// int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); +// if (error == FT_Err_Unknown_File_Format) { +// fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" +// "font format is unsupported\n", filename.c_str()); +// return false; +// } else if (error) { +// fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); +// return false; +// } + +// loadedFonts[filename] = tmp_face; +// fontFace = tmp_face; +// FT_Select_Charmap(fontFace , ft_encoding_unicode); +// } else { +// fontFace = loadedFonts[filename]; +// } + +// return true; +// } + +// void TextureHandler::calculateTextDimensions(std::string text, unsigned int font_size, float& width, float& height) { +// // const wchar_t* string = text.c_str(); +// if(fontFace == nullptr) { //If no font is set, load up a default one +// bool found = false; +// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { +// if (fileExists(DEFAULTFONTPATHS[i])) { +// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW +// loadFont(DEFAULTFONTPATHS[i]); +// found = true; +// break; +// } +// } +// if (!found) { +// TsglErr("No suitable fonts found...exiting"); //NEW +// exit(44); +// } +// } +// FT_GlyphSlot glyph = fontFace->glyph; +// FT_UInt current_glyph_index, previous_glyph_index = 0; +// int penX = 0; +// int penY = 0; + +// int minX = 0; +// int minY = 0; +// int maxX = 0; +// int maxY = 0; + +// int currentRightX, currentTopY, currentBottomY; + +// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); +// if (error) { +// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); +// return; +// } + +// bool use_kerning = FT_HAS_KERNING(fontFace); + +// for (unsigned int i = 0; i < text.size(); i++) { +// current_glyph_index = FT_Get_Char_Index(fontFace, text[i]); + +// if (use_kerning && previous_glyph_index && current_glyph_index) { +// FT_Vector delta; +// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); +// penX += delta.x >> 6; +// penY += delta.y >> 6; +// } + +// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); +// if (error) { +// fprintf(stderr, "FT_Load_Char falied\n"); +// return; +// } + +// previous_glyph_index = current_glyph_index; + +// currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; +// currentTopY = penY - glyph->bitmap_top; +// currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; + +// maxX = currentRightX; +// if(currentBottomY > maxY) { +// maxY = currentBottomY; +// } +// if(currentTopY < minY) { +// minY = currentTopY; +// } + +// penX += glyph->advance.x >> 6; +// penY += glyph->advance.y >> 6; +// } + +// width = maxX - minX; +// height = maxY - minY; +// } + +// /*! +// * \brief Loads an image. +// * \details Loads a .png, .jpeg, or .bmp image from a file. +// * \param filename The file name of the picture. +// * \param width A reference variable for holding the width of the picture. +// * \param height A reference variable for holding the height of the picture. +// * \param texture A reference variable for holding the texture of the picture. +// * (same as return value) +// * \return The texture that created from the loaded image. +// */ +// GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { +// if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already +// texture = 0; +// // stbi_set_flip_vertically_on_load(true); +// // unsigned char * data = stbi_load(filename.c_str(), width, height, 0, 4); +// // tsglAssert(data, "stbi_load(filename) failed."); +// // // create the Image's texture id +// // glGenTextures(1, &texture); +// // glBindTexture(GL_TEXTURE_2D, texture); + +// // // Set texture parameters for wrapping. +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +// // // Set texture parameters for filtering. +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + +// // // actually generate the texture +// // glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +// // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, +// // GL_RGBA, GL_UNSIGNED_BYTE, data); +// // glGenerateMipmap(GL_TEXTURE_2D); + +// std::string extension = filename.substr(filename.find_last_of('.')); +// if (extension == ".png") +// loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); +// else if (extension == ".jpg" || extension == ".jpeg") +// loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); +// else if (extension == ".bmp") +// loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); +// else { +// fprintf(stderr, "File extension not found\n"); +// return 0; +// } +// } else { +// texture = loadedTextures[filename]; +// } + +// return texture; +// } + +// GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself + +// // Data read from the header of the BMP file +// unsigned char header[54]; // Each BMP file begins by a 54-bytes header +// unsigned int imageSize; // = width*height*3 +// // Actual RGB data +// unsigned char * data; + +// // Open the file +// #ifdef _WIN32 +// FILE* file; +// fopen_s(&file, filename, "rb"); +// #else +// FILE* file = fopen(filename, "rb"); +// #endif + +// if (!file) { +// fprintf(stderr, "Can't open %s: no such file\n", filename); +// return 0; +// } + +// if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem +// fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); +// fclose(file); +// return 0; +// } + +// if (header[0] != 'B' || header[1] != 'M') { +// fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); +// fclose(file); +// return 0; +// } + +// imageSize = width = height = 0; +// // Get info out of header as 4 byte unsigned ints +// for (int i = 3; i >= 0; i--) +// imageSize = (imageSize << 8) | header[0x22 + i]; +// for (int i = 3; i >= 0; i--) +// width = (width << 8) | header[0x12 + i]; +// for (int i = 3; i >= 0; i--) +// height = (height << 8) | header[0x16 + i]; + +// int components = imageSize / width / height; + +// // Some BMP files are misformatted, guess missing information +// if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component + +// // Create a buffer +// data = new unsigned char[imageSize]; + +// // Read the actual data from the file into the buffer +// if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem +// fprintf(stderr, "%s: file ended unexpectedly\n", filename); +// fclose(file); +// return 0; +// } + +// //Everything is in memory now, the file can be closed +// fclose(file); + +// char tmp; +// //Reverse the endian-ness of the colors +// if (components == 4) { +// for (unsigned int i = 0; i < imageSize; i += 4) { +// tmp = data[i]; +// data[i] = data[i + 3]; +// data[i + 3] = tmp; +// tmp = data[i + 1]; +// data[i + 1] = data[i + 2]; +// data[i + 2] = tmp; +// } +// } else if (components == 3) { +// for (unsigned int i = 0; i < imageSize; i += 3) { +// tmp = data[i]; +// data[i] = data[i + 1]; +// data[i + 1] = tmp; +// } +// } + +// // Flip the image vertically, since BMPs are loaded bottom to top +// for (unsigned int j = 0; j < height - (height / 2); j++) { +// for (unsigned int i = 0; i < components * width; i++) { +// int s1 = components * width * j + i; +// int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j +// tmp = data[s1]; +// data[s1] = data[s2]; +// data[s2] = tmp; +// } +// } + +// if (components == 3) +// components = GL_RGB; +// else if (components == 4) +// components = GL_RGBA; + +// createGLtextureFromBuffer(texture, data, width, height, components); + +// delete[] data; + +// return texture; +// } + +// /*! +// * \brief Gets the dimensions of an image +// * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. +// * \param filename The file name of the picture. +// * \param width A reference variable for holding the width of the picture. +// * \param height A reference variable for holding the height of the picture. +// * \return The texture that created from the loaded image. +// */ +// void TextureHandler::getDimensions(std::string filename, int &width, int &height) { +// int w = 0, h = 0; +// stbi_info(filename.c_str(), &w, &h, 0); +// width = w; height = h; +// } + +// GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// unsigned char *data; +// int w = 0, h = 0; +// TsglDebug(std::string("Loading ") + filename); +// data = stbi_load(filename, &w, &h, 0, 4); +// assert(data); +// if (!data) { +// TsglErr(std::string("Loading ") + filename + " failed"); +// return texture; +// } +// TsglDebug(std::string("Loading ") + filename + " succeeded"); +// TsglDebug(to_string(w) + "," + to_string(h)); +// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); +// width = w, height = h; +// free(data); +// return texture; +// } + +// GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// unsigned char *data; +// int w = 0, h = 0; +// TsglDebug(std::string("Loading ") + filename); +// data = stbi_load(filename, &w, &h, 0, 4); +// assert(data); +// if (!data) { +// TsglErr(std::string("Loading ") + filename + " failed"); +// return texture; +// } +// TsglDebug(std::string("Loading ") + filename + " succeeded"); +// TsglDebug(to_string(w) + "," + to_string(h)); +// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); +// width = w, height = h; +// free(data); +// return texture; +// } + +// /*! +// * \brief Saves an Image. +// * \details Saves an Image to file that was captured from a Canvas object. +// * \param filename The name of the file to save the Image to. +// * \param pixels The pixel data for the Image. +// * \param width The width of the Image. +// * \param height The height of the Image. +// * \return True if successful, false otherwise. +// */ +// bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, +// unsigned int width, unsigned int height) const { +// std::string extension = filename.substr(filename.find_last_of('.')); +// bool success = false; +// if (extension == ".png") +// success = saveToPNG(filename.c_str(), pixels, width, height); +// else if (extension == ".jpg" || extension == ".jpeg") +// fprintf(stderr, "JPG saving not implemented yet\n"); +// else if (extension == ".bmp") +// success = saveToBMP(filename.c_str(), pixels, width, height); +// else +// fprintf(stderr, "File extension not found\n"); +// return success; +// } + +// bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { +// unsigned char header[54]; // Each BMP file begins by a 54-bytes header +// unsigned int imageSize = w * h * 3; // Byte-size of the data for the image +// unsigned int totalSize = imageSize + 54; + +// // Open the file +// #ifdef _WIN32 +// FILE* file; +// fopen_s(&file, filename, "wb"); +// #else +// FILE* file = fopen(filename, "wb"); +// #endif + +// if (!file) { +// fprintf(stderr, "Can't open %s: no such file\n", filename); +// return false; +// } + +// unsigned char padding = 4 - (w * 3) % 4; +// if (padding == 4) padding = 0; +// int rawdatasize = (w * 3 + padding) * h; + +// header[0] = 'B'; +// header[1] = 'M'; +// header[2] = (unsigned char) totalSize; +// header[3] = (unsigned char)(totalSize >> 8); +// header[4] = (unsigned char)(totalSize >> 16); +// header[5] = (unsigned char)(totalSize >> 24); +// for (unsigned i = 6; i <= 9; ++i) +// header[i] = 0; +// header[10] = 54; +// for (unsigned i = 11; i <= 13; ++i) +// header[i] = 0; +// header[14] = 40; +// for (unsigned i = 15; i <= 17; ++i) +// header[i] = 0; +// header[18] = (unsigned char) w; +// header[19] = (unsigned char)(w >> 8); +// header[20] = (unsigned char)(w >> 16); +// header[21] = (unsigned char)(w >> 24); +// header[22] = (unsigned char) h; +// header[23] = (unsigned char)(h >> 8); +// header[24] = (unsigned char)(h >> 16); +// header[25] = (unsigned char)(h >> 24); +// header[26] = 1; +// header[27] = 0; +// header[28] = 24; +// header[29] = 0; +// for (unsigned i = 30; i <= 33; ++i) +// header[i] = 0; +// header[34] = (unsigned char) rawdatasize; +// header[35] = (unsigned char)(rawdatasize >> 8); +// header[36] = (unsigned char)(rawdatasize >> 16); +// header[37] = (unsigned char)(rawdatasize >> 24); +// header[38] = 19; +// header[39] = 11; +// header[40] = 0; +// header[41] = 0; +// header[42] = 19; +// header[43] = 11; +// header[44] = 0; +// header[45] = 0; +// for (unsigned i = 46; i <= 53; ++i) +// header[i] = 0; + +// unsigned char *rawdata = new unsigned char[rawdatasize]; + +// unsigned rawpos = 0, datapos = 0; +// for (unsigned j = 0; j < h; ++j) { +// for (unsigned i = 0; i < w; ++i) { +// rawdata[rawpos] = pixels[datapos+2]; +// rawdata[rawpos+1] = pixels[datapos+1]; +// rawdata[rawpos+2] = pixels[datapos]; +// rawpos += 3; +// datapos += 3; +// } +// for (unsigned i = 0; i < padding; ++i) { +// rawdata[rawpos++] = 0; +// } +// } + +// fwrite(header, 54, 1, file); +// fwrite(rawdata, 1, rawdatasize, file); +// fclose(file); + +// delete[] rawdata; + +// return true; +// } + +// bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { +// // Flip the image, since for some reason the library call +// // flips the image upside down when it saves +// for (unsigned int j = 0; j < h - (h / 2); j++) { +// for (unsigned int i = 0; i < 3 * w; i++) { +// int s1 = 3 * w * j + i; +// int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j +// char tmp = pixels[s1]; +// pixels[s1] = pixels[s2]; +// pixels[s2] = tmp; +// } +// } +// stbi_write_png(filename, w, h, 3, pixels, 0); +// return true; +// } + +// //-------------------------Unit testing--------------------------------------------- +// /*! +// * \brief Runs the Unit tests for TextureHandler. +// */ +// void TextureHandler::runTests() { +// TsglDebug("Testing TextureHandler class..."); +// TextureHandler tester; +// tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); +// TsglDebug("Unit tests for TextureHandler complete."); +// std::cout << std::endl; +// } + +// bool TextureHandler::testLoadFont(TextureHandler& test) { +// int passed = 0; //Passed tests +// int failed = 0; //Failed tests +// //Test 1: Loading in the font at the start +// if(test.fontFace == nullptr) { +// test.loadFont("../assets/freefont/FreeMono.ttf"); +// if(test.fontFace != nullptr) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Loading font for testLoadFont() failed!"); +// } +// } + +// if(passed == 1 && failed == 0) { +// TsglDebug("Unit test for loading in fonts passed!"); +// return true; +// } else { +// TsglErr("This many tests passed for testLoadFont: "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many tests failed for testLoadFont: "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } +// //----------------------------End Unit testing--------------------------------------- +// } diff --git a/src/TSGL/TextureHandler.h b/src/TSGL/TextureHandler.h index 2017dbf19..9f70384ed 100644 --- a/src/TSGL/TextureHandler.h +++ b/src/TSGL/TextureHandler.h @@ -1,94 +1,97 @@ -/* - * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. - */ - -#ifndef TEXTURELOADER_H_ -#define TEXTURELOADER_H_ - -#include -#include - -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#include // Needed for GL function calls - -#ifdef _WIN32 - #include - #include - #include -//#else -// #include -// #include -#endif - -#include // For GL functions -#include -#include -#include -#include - -#include "Error.h" -#include "TsglAssert.h" // For unit testing purposes -#include "Util.h" // For testing for the existence of files - -typedef GLuint GLtexture; - -namespace tsgl { - -/*! \class TextureHandler - * \brief Handles saving, loading, and rendering of images and textures. - * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas - * and CartesianCanvas through the use of GLTextures. - */ -class TextureHandler { - private: - typedef std::unordered_map TextureMap; - typedef std::unordered_map FontMap; - - TextureMap loadedTextures; - FontMap loadedFonts; - FT_Library fontLibrary; - FT_Face fontFace; - - static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, - const unsigned int &height, int glMode); +// /* +// * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. +// */ + +// #ifndef TEXTURELOADER_H_ +// #define TEXTURELOADER_H_ + +// #include +// #include +// #include +// #include + +// #include FT_FREETYPE_H +// #include FT_GLYPH_H + +// #include // Needed for GL function calls + +// #ifdef _WIN32 +// #include +// #include +// #include +// //#else +// // #include +// // #include +// #endif + +// #include // For GL functions +// #include +// #include +// #include +// #include +// #include + +// #include "Error.h" +// #include "TsglAssert.h" // For unit testing purposes +// #include "Util.h" // For testing for the existence of files + +// typedef GLuint GLtexture; + +// namespace tsgl { + +// /*! \class TextureHandler +// * \brief Handles saving, loading, and rendering of images and textures. +// * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas +// * and CartesianCanvas through the use of GLTextures. +// */ +// class TextureHandler { +// private: +// typedef std::unordered_map TextureMap; +// typedef std::unordered_map FontMap; + +// TextureMap loadedTextures; +// FontMap loadedFonts; +// FT_Library fontLibrary; +// FT_Face fontFace; + +// static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, +// const unsigned int &height, int glMode); - GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; - GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; - GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; +// GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; +// GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; +// GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; - bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; - bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; +// bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; +// bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; - static bool testLoadFont(TextureHandler& test); +// static bool testLoadFont(TextureHandler& test); - public: - TextureHandler(); +// public: +// TextureHandler(); - ~TextureHandler(); +// ~TextureHandler(); - bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); +// bool drawText(std::string text, unsigned int font_size, float* vertices); - bool loadFont(const std::string& filename); +// bool loadFont(const std::string& filename); - void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); +// void calculateTextDimensions(std::string text, unsigned int font_size, float& width, float& height); - static void getDimensions(std::string filename, int &width, int &height); +// static void getDimensions(std::string filename, int &width, int &height); - GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); +// GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); - bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; +// bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; - void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); +// void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); - static void runTests(); -}; +// static void runTests(); +// }; -} +// } -#endif /* TEXTURELOADER_H_ */ +// #endif /* TEXTURELOADER_H_ */ diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index 9b7f64401..c7808c7ee 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -3,118 +3,64 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Triangle with monocolored fill or outline. + * \brief Explicitly constructs a new Triangle with monocolored fill. * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. + * \param z1 The z coordinate of the first endpoint. * \param x2 The x coordinate of the second endpoint. * \param y2 The y coordinate of the second endpoint. + * \param z2 The z coordinate of the second endpoint. * \param x3 The x coordinate of the third endpoint. * \param y3 The y coordinate of the third endpoint. + * \param z3 The z coordinate of the third endpoint. + * \param yaw The yaw of the triangle's rotation. + * \param pitch The pitch of the triangle's rotation. + * \param roll The roll of the triangle's rotation. * \param color The color of the Triangle. - * \param filled Whether the Triangle should be filled - * (set to true by default). * \return A new Triangle with the specified vertices and color. */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color, bool filled) : ConvexPolygon(3, filled, !filled) { - addVertex(x1, y1, color); - addVertex(x2, y2, color); - addVertex(x3, y3, color); +Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { + float xAverage = (x1 + x2 + x3) / 3; + float yAverage = (y1 + y2 + y3) / 3; + float zAverage = (z1 + z2 + z3) / 3; + addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color); + addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color); + addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color); + addOutlineVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, GRAY); + addOutlineVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, GRAY); + addOutlineVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, GRAY); + geometryType = GL_TRIANGLES; } /*! - * \brief Explicitly constructs a new Triangle with multicolored fill or outline. + * \brief Explicitly constructs a new Triangle with multicolored fill. * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. + * \param z1 The z coordinate of the first endpoint. * \param x2 The x coordinate of the second endpoint. * \param y2 The y coordinate of the second endpoint. + * \param z2 The z coordinate of the second endpoint. * \param x3 The x coordinate of the third endpoint. * \param y3 The y coordinate of the third endpoint. + * \param z3 The z coordinate of the third endpoint. + * \param yaw The yaw of the triangle's rotation. + * \param pitch The pitch of the triangle's rotation. + * \param roll The roll of the triangle's rotation. * \param color An array of colors for the Triangle's vertices. - * \param filled Whether the Triangle should be filled - * (set to true by default). * \return A new Triangle with the specified vertices and color. */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color[], bool filled) : ConvexPolygon(3, filled, !filled) { - addVertex(x1, y1, color[0]); - addVertex(x2, y2, color[1]); - addVertex(x3, y3, color[2]); -} - -/*! - * \brief Explicitly constructs a new Triangle with different monocolored fill and outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor The color of the Triangle's fill. - * \param outlineColor The color of the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor, outlineColor); - addVertex(x2, y2, fillColor, outlineColor); - addVertex(x3, y3, fillColor, outlineColor); -} - -/*! - * \brief Explicitly constructs a new Triangle with multicolored fill and monocolored outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor The color of the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor[0], outlineColor); - addVertex(x2, y2, fillColor[1], outlineColor); - addVertex(x3, y3, fillColor[2], outlineColor); -} - -/*! - * \brief Explicitly constructs a new Triangle with monocolored fill and multicolored outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor The color of the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor, outlineColor[0]); - addVertex(x2, y2, fillColor, outlineColor[1]); - addVertex(x3, y3, fillColor, outlineColor[2]); -} - -/*! - * \brief Explicitly constructs a new Triangle with different multicolored fill and outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor[0], outlineColor[0]); - addVertex(x2, y2, fillColor[1], outlineColor[1]); - addVertex(x3, y3, fillColor[2], outlineColor[2]); +Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { + float xAverage = (x1 + x2 + x3) / 3; + float yAverage = (y1 + y2 + y3) / 3; + float zAverage = (z1 + z2 + z3) / 3; + addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color[0]); + addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color[1]); + addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color[2]); + addOutlineVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, GRAY); + addOutlineVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, GRAY); + addOutlineVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, GRAY); + geometryType = GL_TRIANGLES; } } diff --git a/src/TSGL/Triangle.h b/src/TSGL/Triangle.h index 9a533108d..e6aea02e6 100755 --- a/src/TSGL/Triangle.h +++ b/src/TSGL/Triangle.h @@ -17,17 +17,9 @@ class Triangle : public ConvexPolygon { private: public: - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color, bool filled = true); + Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color); - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color[], bool filled = true); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[]); }; } diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index f67bcdd33..f0fb3bdcb 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -3,100 +3,60 @@ namespace tsgl { /*! - * \brief Explicitly construct a new TriangleStrip with monocolored fill or outline. + * \brief Explicitly construct a new TriangleStrip with monocolored fill. * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param color The color of the TriangleStrip - * \param filled Whether the TriangleStrip should be filled - * (set to true by default). + * \param centerX The x coordinate of the center of the TriangleStrip. + * \param centerY The y coordinate of the center of the TriangleStrip. + * \param centerZ The z coordinate of the center of the TriangleStrip. + * \param numVertices The number of vertices. + * \param x An array of numVertices x parameters for the vertices of the TriangleStrip. + * \param y An array of numVertices y parameters for the vertices of the TriangleStrip. + * \param z An array of numVertices z parameters for the vertices of the TriangleStrip. + * \param yaw The TriangleStrip's yaw. + * \param pitch The TriangleStrip's pitch. + * \param roll The TriangleStrip's roll. + * \param color The color of the TriangleStrip * \return A new TriangleStrip with the specified vertices and color. */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat color, bool filled) : ConvexPolygon(numVertices, filled, !filled) { +TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + isOutlined = false; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } /*! - * \brief Explicitly construct a new TriangleStrip with multicolored fill or outline. + * \brief Explicitly construct a new TriangleStrip with multicolored fill. * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param color An array of colors for the TriangleStrip - * \param filled Whether the TriangleStrip should be filled - * (set to true by default). + * \param centerX The x coordinate of the center of the TriangleStrip. + * \param centerY The y coordinate of the center of the TriangleStrip. + * \param centerZ The z coordinate of the center of the TriangleStrip. + * \param numVertices The number of vertices. + * \param x An array of numVertices x parameters for the vertices of the TriangleStrip. + * \param y An array of numVertices y parameters for the vertices of the TriangleStrip. + * \param z An array of numVertices z parameters for the vertices of the TriangleStrip. + * \param yaw The TriangleStrip's yaw. + * \param pitch The TriangleStrip's pitch. + * \param roll The TriangleStrip's roll. + * \param color An array of colors for the TriangleStrip * \return A new TriangleStrip with the specified vertices and color. */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : ConvexPolygon(numVertices, filled, !filled) { +TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + isOutlined = false; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with different monocolored fill and outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor The color of the TriangleStrip's fill. - * \param outlineColor The color of the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with multicolored fill and monocolored outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor An array of colors for the TriangleStrip's fill. - * \param outlineColor The color of the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with monocolored fill and multicolored outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor The color of the TriangleStrip's fill. - * \param outlineColor An array of colors for the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with different multicolored fill and outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor An array of colors for the TriangleStrip's fill. - * \param outlineColor An array of colors for the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } } diff --git a/src/TSGL/TriangleStrip.h b/src/TSGL/TriangleStrip.h index db8052c46..03cb8b94d 100755 --- a/src/TSGL/TriangleStrip.h +++ b/src/TSGL/TriangleStrip.h @@ -24,17 +24,9 @@ class TriangleStrip : public ConvexPolygon { private: public: - TriangleStrip(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); + TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color); - TriangleStrip(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); + TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[]); }; } diff --git a/src/TSGL/Util.h b/src/TSGL/Util.h index 65ee4b25e..248613903 100644 --- a/src/TSGL/Util.h +++ b/src/TSGL/Util.h @@ -6,6 +6,8 @@ #define SRC_TSGL_UTIL_H_ #include //To determine M_PI and is also used for math operations +#include //Used for multithreaded capabilities of saferand() +#include //Used to generate random numbers in saferand() namespace tsgl { @@ -14,14 +16,23 @@ class CartesianCanvas; //Forward declaration for typedef //Constants to be used by TSGL classes and tests #ifdef _WIN32 const double PI = 3.14159265358979323846; +const double TWOPI = PI * 2; +#elif __CYGWIN__ +const double PI = 3.14159265358979323846; +const double TWOPI = PI * 2; #else const double PI = M_PI; +const double TWOPI = PI * 2; #endif const double RAD = PI / 180; // One radian in degrees const int FPS = 60; // Frames per second const float FRAME = 1.0f/FPS; // Number of seconds between frames +const unsigned int TEXT_SHADER_TYPE = 0; +const unsigned int SHAPE_SHADER_TYPE = 1; +const unsigned int TEXTURE_SHADER_TYPE = 2; + /*! * \var typedef long double Decimal * \brief A type definition for a long double. @@ -128,6 +139,53 @@ inline bool fileExists (const std::string& name) { #endif } +// thanks to Rani Hod of Tel Aviv University for this function. +// slightly modified by Ian Adams of Calvin University to add min, max +/*! + * \brief Thread-safe random integer generator + * \details Calling this method returns a randomly generated number between min, max params. + * Repeated calls will result in uniformly distributed random variables. + * \param min Minimum integer value that can be generated by the method, inclusive. + * \param max Maximum integer value that can be generated by the method, inclusive. + * \note Thanks to Rani Hod of Tel Aviv University for this function. Modified by Ian Adams of Calvin University to add min, max. + */ +inline int saferand(int min, int max) +{ + static std::mt19937* generator = nullptr; + #pragma omp threadprivate(generator) + std::uniform_int_distribution dis(min, max); + if (!generator) { + unsigned seed = clock() + omp_get_thread_num(); + generator = new std::mt19937(seed); + } + int val = dis(*generator); + return val; + // return (*generator)(); +} + + /*! + * \brief Thread safe random float generator + * \details Calculates a random float to return. + * \param divisor Divisor used to calculate the random float. + */ +inline float randfloat(int divisor = 10000) { + return (float) saferand(0, divisor) / divisor; +} + +/*! + * \brief Calculates distance between two points in 3D space. + * \details Applies the distance formula to the corresponding parameters. + * \param x1 x-coordinate of the first point. + * \param y1 y-coordinate of the first point. + * \param z1 z-coordinate of the first point. + * \param x2 x-coordinate of the second point. + * \param y2 y-coordinate of the second point. + * \param z2 z-coordinate of the second point. + */ +inline float distanceBetween(float x1, float y1, float z1, float x2, float y2, float z2) { + return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow (z2 - z1, 2)); +} + } #endif /* SRC_TSGL_UTIL_H_ */ diff --git a/src/TSGL/VisualTaskQueue.cpp b/src/TSGL/VisualTaskQueue.cpp index 077794257..f8f04f08e 100644 --- a/src/TSGL/VisualTaskQueue.cpp +++ b/src/TSGL/VisualTaskQueue.cpp @@ -25,7 +25,7 @@ VisualTaskQueue::VisualTaskQueue(int elements, int sideLength, float aspect, int blockSize = sideLength; vcan = new Canvas(0,-1,2*border+(blockSize+space)*rowLength,2*border+(blockSize+space)*elements/rowLength,"Thread colors"); vcan->start(); - reset(); + // reset(); } /*! @@ -46,51 +46,41 @@ VisualTaskQueue::~VisualTaskQueue() { * \param threads The number of threads the VisualTaskQueue is using. */ void VisualTaskQueue::showLegend(int threads) { - bool canContinue = false; - #pragma omp critical - { - if (!showingLegend) { - showingLegend = true; - canContinue = true; - } - } - if (canContinue) { - const int TEXTW = 24, GAP = 4; - if (threads == -1) - threads = omp_get_num_threads(); + showingLegend = true; + const int TEXTW = 24, GAP = 4; + if (threads == -1) + threads = omp_get_num_threads(); - //Ugly calculations :( - int offset = border+space; - int xStart = border; - int xDelta = TEXTW*2; - int yStart = TEXTW + offset; - int yDelta = blockSize+space; - int oheight = vcan->getWindowHeight(); - int myHeight = TEXTW + (threads+1) * yDelta; - if (myHeight > oheight) - myHeight = oheight; - int perColumn = (myHeight-yStart)/yDelta; - int yCutoff = yStart + yDelta*perColumn-blockSize; - int myWidth = 2*border + ((threads)/perColumn)*xDelta+blockSize+TEXTW; - #ifdef _WIN32 - if (myWidth < 116); //Magic number for Windows windows... - myWidth = 116; - #endif + //Ugly calculations :( + int offset = border+space; + int xStart = border; + int xDelta = TEXTW*2; + int yStart = TEXTW + offset; + int yDelta = blockSize+space; + int oheight = vcan->getWindowHeight(); + int myHeight = TEXTW + (threads+1) * yDelta; + if (myHeight > oheight) + myHeight = oheight; + int perColumn = (myHeight-yStart)/yDelta; + int yCutoff = yStart + yDelta*perColumn-blockSize; + int myWidth = 2*border + ((threads)/perColumn)*xDelta+blockSize+TEXTW; +#ifdef _WIN32 +if (myWidth < 116); //Magic number for Windows windows... +myWidth = 116; +#endif - //Actually draw things - lcan = new Canvas(vcan->getWindowX()+vcan->getWindowWidth(),vcan->getWindowY(),myWidth,myHeight,""); - std::cout << lcan->getWindowWidth(); - lcan->start(); - lcan->drawText("Legend:",TEXTW/2,TEXTW,TEXTW,BLACK); - int xx = xStart, yy = yStart; - for (int i = 0; i < threads; ++i) { - lcan->drawRectangle(xx,yy,blockSize,blockSize,Colors::highContrastColor(i)); - lcan->drawText(to_string(i),xx+blockSize+GAP,yy+blockSize,TEXTW/2); - yy += yDelta; - if (yy > yCutoff) { - yy = yStart; - xx += xDelta; - } +// //Actually draw things + lcan = new Canvas(vcan->getWindowX()+vcan->getWindowWidth(),vcan->getWindowY(),myWidth,myHeight,""); + lcan->start(); + lcan->getBackground()->drawText(0,lcan->getWindowHeight()/2-TEXTW/2,0,"Legend:","./assets/freefont/FreeSerif.ttf",TEXTW,0,0,0,BLACK); + int xx = -lcan->getWindowWidth()/2 + xStart, yy = lcan->getWindowHeight()/2 - yStart; + for (int i = 0; i < threads; ++i) { + lcan->getBackground()->drawSquare(xx,yy,0,blockSize,0,0,0,Colors::highContrastColor(i)); + lcan->getBackground()->drawText(xx+blockSize+GAP,yy,0,std::to_wstring(i),"./assets/freefont/FreeSerif.ttf",TEXTW/2,0,0,0,BLACK); + yy -= yDelta; + if (yy > yCutoff) { + yy = yStart; + xx += xDelta; } } } @@ -104,12 +94,13 @@ void VisualTaskQueue::showLegend(int threads) { void VisualTaskQueue::update(int index, VQState state) { int x = index % rowLength; int y = index / rowLength; - vcan->drawRectangle( - border+x*(blockSize+space),border+y*(blockSize+space), - blockSize,blockSize, + vcan->getBackground()->drawSquare( + border*2+x*(blockSize+space)-vcan->getWindowWidth()/2,vcan->getWindowHeight()/2 - (border * 1.5+y*(blockSize+space)),0, + blockSize, + 0,0,0, Colors::blend( Colors::highContrastColor(omp_get_thread_num()),(state == RUNNING) ? BLACK : WHITE,0.5f - ),true + ) ); } @@ -121,10 +112,11 @@ void VisualTaskQueue::reset() { for (int i = 0; i < totalElements; ++i) { int x = i % rowLength; int y = i / rowLength; - vcan->drawRectangle( - border+x*(blockSize+space),border+y*(blockSize+space), - blockSize,blockSize, - WHITE,true + vcan->getBackground()->drawSquare( + border*2+x*(blockSize+space)-vcan->getWindowWidth()/2,vcan->getWindowHeight()/2 - (border * 1.5+y*(blockSize+space)),0, + blockSize, + 0,0,0, + WHITE ); } } @@ -135,18 +127,19 @@ void VisualTaskQueue::reset() { * \warning Do not attempt to reset() or update() the VisualTaskQueue after closing it. */ void VisualTaskQueue::close() { - if (lcan->isOpen()) - lcan->close(); - lcan->wait(); if (showingLegend) { - if (vcan->isOpen()) - vcan->close(); - vcan->wait(); - } + if (lcan->isOpen()) + lcan->close(); + lcan->wait(); + } + if (vcan->isOpen()) + vcan->close(); + vcan->wait(); } void VisualTaskQueue::sleep() { - lcan->sleep(); + if (showingLegend) + lcan->sleep(); vcan->sleep(); } diff --git a/src/TSGL/gl_includes.h b/src/TSGL/gl_includes.h new file mode 100644 index 000000000..9c11ab497 --- /dev/null +++ b/src/TSGL/gl_includes.h @@ -0,0 +1,11 @@ +/* + * gl_includes.h + */ + +#ifndef GL_INCLUDES_H_ +#define GL_INCLUDES_H_ + +#include // Needed for GL function calls +#include // For window creation and management + +#endif /* GL_INCLUDES_H_ */ \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/CubeArray.cpp b/src/examples/ArrayBubbleSort/CubeArray.cpp new file mode 100644 index 000000000..55925b5f0 --- /dev/null +++ b/src/examples/ArrayBubbleSort/CubeArray.cpp @@ -0,0 +1,258 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Default constructor for CubeArray. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hide it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the size of the CubeArray's Text/numbers to a new size. + * \param size The new size. + */ +void CubeArray::setTextSize(float size){ + for(Text * t : myText){ + t->setSize(size); + } +} + +/** + * \brief Changes the CubeArray's yaw by a given value. + * \param yaw The yaw to add to the CubeArray's current yaw. + */ +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +/** + * \brief Changes the CubeArray's pitch by a given value. + * \param pitch The pitch to add to the CubeArray's current pitch. + */ +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +/** + * \brief Changes the CubeArray's roll by a given value. + * \param roll The roll to add to the CubeArray's current roll. + */ +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/CubeArray.h b/src/examples/ArrayBubbleSort/CubeArray.h new file mode 100644 index 000000000..926f9fba4 --- /dev/null +++ b/src/examples/ArrayBubbleSort/CubeArray.h @@ -0,0 +1,72 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setTextSize(float size); + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + // Operations + CubeArray operator+ (CubeArray& c2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/Makefile b/src/examples/ArrayBubbleSort/Makefile new file mode 100644 index 000000000..f9e77e449 --- /dev/null +++ b/src/examples/ArrayBubbleSort/Makefile @@ -0,0 +1,87 @@ +# Makefile for ArrayBubbleSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrayBubbleSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp b/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp new file mode 100644 index 000000000..d8fdfa196 --- /dev/null +++ b/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp @@ -0,0 +1,137 @@ +/* + * testArrayBubbleSort.cpp + * + * Usage: ./testArrayBubbleSort [sizeOfArray] + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; +} + +void sortVisualizationFunction(Canvas& can, int arraySize) { + // Create arrays to perform operation on + int originalArray[arraySize]; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = saferand(0, RAND_UPPER + 1); + } + + printf("Before bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Bubble Sort", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + can.add(titleLabel); + + float sleepTime = 0.125; // initial number of seconds to sleep + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0){ + int end = arraySize; + // Bubble sort algorithm + for(unsigned i = 0; i < arrayA.getSize(); i++){ + for(unsigned j = 1; j < end; j++){ // OR j < arrayA.getSize(); + arrayA.getCube(j)->setColor(RED); + arrayA.getCube(j-1)->setColor(BLUE); + can.sleepFor(sleepTime); + if(arrayA[j] < arrayA[j-1]){ + swap(arrayA[j], arrayA[j-1]); + arrayA.update(j); + arrayA.update(j-1); + can.sleepFor(sleepTime); + } + arrayA.getCube(j)->setColor(ARRAY_COLOR); + arrayA.getCube(j-1)->setColor(ARRAY_COLOR); + can.sleepFor(sleepTime); + } + arrayA.getCube(end-1)->setColor(FINISHED_COLOR); + end--; + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + delete titleLabel; + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int sizeOfArray = (argc > 1) ? atoi(argv[1]) : 10; + + // Checks validity of sizeOfArray; if invalid, set to default + if((sizeOfArray <= 0 or sizeOfArray > 24)){ + printf("Invalid argument(s).\ + \nUsage: ./testArrayBubbleSort [sizeOfArray]\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + sizeOfArray = 10; + } + + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Array Bubble Sort", BLACK); + c.run(sortVisualizationFunction, sizeOfArray); +} diff --git a/src/examples/ArrayShakerSort/CubeArray.cpp b/src/examples/ArrayShakerSort/CubeArray.cpp new file mode 100644 index 000000000..55925b5f0 --- /dev/null +++ b/src/examples/ArrayShakerSort/CubeArray.cpp @@ -0,0 +1,258 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Default constructor for CubeArray. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hide it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the size of the CubeArray's Text/numbers to a new size. + * \param size The new size. + */ +void CubeArray::setTextSize(float size){ + for(Text * t : myText){ + t->setSize(size); + } +} + +/** + * \brief Changes the CubeArray's yaw by a given value. + * \param yaw The yaw to add to the CubeArray's current yaw. + */ +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +/** + * \brief Changes the CubeArray's pitch by a given value. + * \param pitch The pitch to add to the CubeArray's current pitch. + */ +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +/** + * \brief Changes the CubeArray's roll by a given value. + * \param roll The roll to add to the CubeArray's current roll. + */ +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/CubeArray.h b/src/examples/ArrayShakerSort/CubeArray.h new file mode 100644 index 000000000..926f9fba4 --- /dev/null +++ b/src/examples/ArrayShakerSort/CubeArray.h @@ -0,0 +1,72 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setTextSize(float size); + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + // Operations + CubeArray operator+ (CubeArray& c2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/Makefile b/src/examples/ArrayShakerSort/Makefile new file mode 100644 index 000000000..c2e239c7b --- /dev/null +++ b/src/examples/ArrayShakerSort/Makefile @@ -0,0 +1,87 @@ +# Makefile for ArrayShakerSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrayShakerSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/testArrayShakerSort.cpp b/src/examples/ArrayShakerSort/testArrayShakerSort.cpp new file mode 100644 index 000000000..34ddd0c99 --- /dev/null +++ b/src/examples/ArrayShakerSort/testArrayShakerSort.cpp @@ -0,0 +1,178 @@ +/* + * testArrayShakerSort.cpp + * + * Usage: ./testArrayShakerSort [sizeOfArray] + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; +} + +void sortVisualizationFunction(Canvas& can, int arraySize) { + // Create arrays to perform operation on + int originalArray[arraySize]; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = saferand(0, RAND_UPPER + 1); + } + + printf("Before shaker sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Shaker Sort", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw label on canvas + can.add(titleLabel); + + float sleepTime = 0.5; // number of seconds to sleep + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + bool swapped = true; + int start = 0; + int end = arraySize - 1; + while (can.isOpen()) { + can.sleep(); + + if(complete == 0){ + // Shaker sort + while (swapped) { + // reset the swapped flag on entering + // the loop, because it might be true from + // a previous iteration. + swapped = false; + + // Going up + for (int pos = start; pos < end; ++pos) { + arrayA.getCube(pos)->setColor(RED); + arrayA.getCube(pos+1)->setColor(BLUE); + can.sleepFor(sleepTime); + // Compare values + if (arrayA[pos] > arrayA[pos + 1]) { + swap(arrayA[pos], arrayA[pos + 1]); + swapped = true; + arrayA.update(pos); arrayA.update(pos + 1); + } + // Animation + can.sleepFor(sleepTime); + arrayA.getCube(pos)->setColor(ARRAY_COLOR); + arrayA.getCube(pos+1)->setColor(ARRAY_COLOR); + } + // if nothing moved, then array is sorted. + if (!swapped) + break; + + // otherwise, reset the swapped flag so that it + // can be used in the next stage + swapped = false; + arrayA.getCube(end)->setColor(FINISHED_COLOR); + --end; + + // Going down + for (int pos = end - 1; pos >= start; --pos) { + arrayA.getCube(pos)->setColor(RED); + arrayA.getCube(pos+1)->setColor(BLUE); + can.sleepFor(sleepTime); + if (arrayA[pos] > arrayA[pos + 1]) { + swap(arrayA[pos], arrayA[pos + 1]); + swapped = true; + arrayA.update(pos); arrayA.update(pos + 1); + } + // Animation + can.sleepFor(sleepTime); + arrayA.getCube(pos)->setColor(ARRAY_COLOR); + arrayA.getCube(pos+1)->setColor(ARRAY_COLOR); + } + arrayA.getCube(start)->setColor(FINISHED_COLOR); + ++start; + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter shaker sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + delete titleLabel; + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int sizeOfArray = (argc > 1) ? atoi(argv[1]) : 10; + + // Checks validity of sizeOfArray; if invalid, set to default + if((sizeOfArray <= 0 or sizeOfArray > 24)){ + printf("Invalid argument(s).\ + \nUsage: ./testArrayShakerSort [sizeOfArray]\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + sizeOfArray = 10; + } + + printf("Use the up and down arrow keys to speed up and slow down animation, respectfully.\n"); + + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Array Shaker Sort", BLACK); + c.run(sortVisualizationFunction, sizeOfArray); +} + + + diff --git a/src/examples/Ballroom/Makefile b/src/examples/Ballroom/Makefile new file mode 100644 index 000000000..132db3296 --- /dev/null +++ b/src/examples/Ballroom/Makefile @@ -0,0 +1,87 @@ +# Makefile for Ballroom + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBallroom + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBallroom.cpp b/src/examples/Ballroom/testBallroom.cpp similarity index 87% rename from src/tests/testBallroom.cpp rename to src/examples/Ballroom/testBallroom.cpp index dfb41cafb..92f9a42e1 100644 --- a/src/tests/testBallroom.cpp +++ b/src/examples/Ballroom/testBallroom.cpp @@ -89,8 +89,7 @@ class BouncingBall { rh = h; color = c; bounced = false; - circle = new Circle(x,y,r,c); - circle->setLayer(1); + circle = new Circle(x,y,0,r,0,0,0,c); can->add(circle); } BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorFloat c, Canvas * canvas) { @@ -105,8 +104,7 @@ class BouncingBall { color = c; bounced = false; can = canvas; - circle = new Circle(x,y,r,c); - circle->setLayer(1); + circle = new Circle(x,y,0,r,0,0,0,c); can->add(circle); } ~BouncingBall() { @@ -133,23 +131,23 @@ class BouncingBall { bounced = false; vel += acc; pos += vel; - if (pos.x <= rad) { - pos.x = rad; + if (pos.x <= -rw / 2 + rad) { + pos.x = -rw / 2 + rad; vel.x *= -0.5f; - } else if (pos.x >= rw-rad) { - pos.x = rw-rad; + } else if (pos.x >= rw / 2 -rad) { + pos.x = rw / 2-rad; vel.x *= -0.5f; } - if (pos.y <= rad) { - pos.y = rad; + if (pos.y <= -rh / 2 + rad) { + pos.y = -rh / 2 + rad; vel.y *= -1.0f; - } else if (pos.y >= rh-rad) { - pos.y = rh-rad; + } else if (pos.y >= rh / 2 -rad) { + pos.y = rh / 2 -rad; vel.y *= -1.0f; } calcSpeed(); calcDir(); - circle->setCenter(pos.x,pos.y); + circle->setCenter(pos.x,pos.y,0); } void setRoomSize(int w, int h) { rw = w; @@ -173,7 +171,7 @@ class BouncingBall { o->calcSpeed(); o->calcDir(); bounced = true; - circle->setCenter(pos.x, pos.y); + circle->setCenter(pos.x, pos.y,0); } bool collides(BouncingBall *o) { return ((pos-o->pos).length() <= (rad+o->rad)); @@ -197,8 +195,7 @@ class BallRoom { gravity = 0.1f; attract = true; can = canvas; - mouseCircle = new Circle(0,0,25,ColorFloat(1.0f,0.5f,0.5f,0.5f)); - mouseCircle->setLayer(2); + mouseCircle = new Circle(0,0,0,20,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); can->add(mouseCircle); } ~BallRoom() { @@ -230,11 +227,11 @@ class BallRoom { void step(Canvas* c) { int mx = c->getMouseX(), my = c->getMouseY(); Vector2 mvec(mx,my); - mouseCircle->setCenter(mx, my); + mouseCircle->setCenter(mx, my, 0); if (attract) { - mouseCircle->setColor(ColorFloat(0.5f,1.0f,1.0f,0.5f)); + mouseCircle->setColor(ColorFloat(0.5,1.0,1.0,0.5)); } else { - mouseCircle->setColor(ColorFloat(1.0f,0.5f,0.5f,0.5f)); + mouseCircle->setColor(ColorFloat(1.0,0.5,0.5,0.5)); } for (it = balls.begin(); it != balls.end(); ++it) { BouncingBall *b = (*it); @@ -289,19 +286,17 @@ void ballroomFunction(Canvas& can) { const int WW = can.getWindowWidth(), // Window width WH = can.getWindowHeight(); // Window height BallRoom b(WW,WH, &can); - srand(time(NULL)); for (int i = 0; i < 100; ++ i) { float speed = 5.0f; - float dir = 2 * 3.14159f * (rand() % 100) / 100.0f; - b.addBall(25 + rand() % (WW-50),25 + rand() % (WH-50),speed*cos(dir),speed*sin(dir),10, - ColorInt(64 + rand() % 192,64 + rand() % 192,64 + rand() % 192,255)); + float dir = 2 * PI * saferand(0,100) / 100.0f; + ColorInt c = ColorInt(64 + saferand(0,191),64 + saferand(0,191),64 + saferand(0,191),255); + b.addBall(saferand(-WW/2,WW/2), saferand(-WH/2, WH/2), speed*cos(dir),speed*sin(dir),10,c); } can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { b.toggleAttract(); }); -// ColorFloat clearcolor = ColorInt(0,0,0,16); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class @@ -315,7 +310,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "The Ballroom"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "The Ballroom", BLACK); c.run(ballroomFunction); } diff --git a/src/examples/Clock/Makefile b/src/examples/Clock/Makefile new file mode 100644 index 000000000..35491a5b7 --- /dev/null +++ b/src/examples/Clock/Makefile @@ -0,0 +1,87 @@ +# Makefile for Clock + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testClock + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Clock/testClock.cpp b/src/examples/Clock/testClock.cpp new file mode 100644 index 000000000..4435ddccd --- /dev/null +++ b/src/examples/Clock/testClock.cpp @@ -0,0 +1,107 @@ +/* + * testClock.cpp + * + * Usage: ./testClock + */ + +#include +#include +#include + +using namespace tsgl; + +void clockFunction(Canvas& can) { + Prism * head = new Prism(0,133,101,12,100,59,0,0,90,ColorFloat(.6,.3,0,1)); + can.add(head); + + Cuboid * left = new Cuboid(-45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(left); + + Cuboid * right = new Cuboid(45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1)); + can.add(right); + + Cuboid * back = new Cuboid(0,-50,55,80,300,10,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(back); + + Cuboid * bottom = new Cuboid(0,-195,110,79,10,80,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(bottom); + + Circle * face = new Circle(0,130,161,45,0,0,0,ColorFloat(1,1,0.8,1)); + can.add(face); + + Arrow * second = new Arrow(-19,130,163,38,2,0,0,0,ColorFloat(1,.8,.2,1),false); + can.add(second); + second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * minute = new Arrow(-19,130,162,38,2,0,0,0,BLACK,false); + can.add(minute); + minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * hour = new Arrow(-10,130,162,20,2,0,0,0,BLACK,false); + can.add(hour); + hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Ellipsoid * pendulum = new Ellipsoid(0, -150, 100,10, 10,2,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); + pendulum->setRotationPoint(0,80,10); + can.add(pendulum); + + Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); + cord->setIsOutlined(false); + cord->setRotationPoint(0,80,10); + can.add(cord); + + time_t t = time(NULL); + // printf("local: %s", asctime(localtime(&t))); + // printf("local: %d:%d:%d\n", localtime(&t)->tm_hour, localtime(&t)->tm_min, localtime(&t)->tm_sec); + + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + + float speed = -0.28; + bool accelerationPositive = true; + while (can.isOpen()) { + can.sleep(); + t = time(NULL); + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + if (cord->getYaw() > 97 || cord->getYaw() < 83) { + speed = 0; + } + if (cord->getYaw() > 90 && accelerationPositive == true) { + accelerationPositive = false; + } else if (cord->getYaw() < 90 && accelerationPositive == false) { + accelerationPositive = true; + } + if (accelerationPositive) { + speed += 0.01; + } else { + speed -= 0.01; + } + cord->changeYawBy(speed); + pendulum->changeYawBy(speed); + + } + + delete head; + delete left; + delete right; + delete back; + delete bottom; + delete face; + delete second; + delete minute; + delete hour; + delete pendulum; + delete cord; +} + +int main(int argc, char* argv[]) { + // int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + // int h = (argc > 2) ? atoi(argv[2]) : w; + // if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + // w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 500, 700, "Grandfather Clock", WHITE); + c.run(clockFunction); +} \ No newline at end of file diff --git a/src/tests/Conway/LifeFarm.cpp b/src/examples/Conway/LifeFarm.cpp similarity index 97% rename from src/tests/Conway/LifeFarm.cpp rename to src/examples/Conway/LifeFarm.cpp index bd6bb9ff5..1381f73d8 100644 --- a/src/tests/Conway/LifeFarm.cpp +++ b/src/examples/Conway/LifeFarm.cpp @@ -34,7 +34,7 @@ LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { for (int i = 9*h/10; i > h/10; --i) { bool newrow = true; for (int j = 9*w/10; j > w/10; --j) { - if ((rand() % 2) > 0) { + if ((saferand(1,100) % 2) > 0) { if (newrow) { *currentstate = (i + 1); ++currentstate; @@ -61,6 +61,7 @@ LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { void LifeFarm::initGun() { int w = width/2, h = height/2; + // int w = 0, h = 0; currentstart = currentstate; *currentstate++ = h+1; *currentstate++ = -(w+25); @@ -212,6 +213,8 @@ void LifeFarm::moveAntsOld() { //Reset the end of the list for the next iteration listend = 0; + Background * bg = can->getBackground(); + //Redraw any cell whose living status has changed, and repopulate the living list bool lives, lived; for (int row = 0; row < height; ++row) { @@ -220,11 +223,11 @@ void LifeFarm::moveAntsOld() { lives = ( (neighbors[row][col] == 3) || ( lived && (neighbors[row][col] == 2) )); if (lives != lived) { if (lives) { - can->drawPoint(col, row, fcolor); + bg->drawPixel(col - width/2, height/2 - row, fcolor); addAnt(col,row); } else if (drawdead) - can->drawPoint(col, row, bgcolor); + bg->drawPixel(col - width/2, height/2 - row, bgcolor); alive[row][col] = lives; } else if (lives) addAnt(col,row); @@ -346,7 +349,7 @@ void LifeFarm::life(int *current, int *fresh) { /* what does this bitmap indicate? */ if(state[bitmap] && !(y > height-3 || y < 3) && !((-x) > width-3 || (-x) < 3)) { //If our bitmap is now alive *(++fresh) = x - 1; //Increment the cell pointer of our new board, and set the next value to the current x-coordinate minus 1 - can->drawPoint(-(x), y, fcolor); //Draw it + can->getBackground()->drawPixel(-(x), height / 2 - y, fcolor); //Draw it } else if(bitmap == 000) //If our bitmap is now empty... break; //No more consecutive living cells; move on to the next explicitly stored pointer diff --git a/src/tests/Conway/LifeFarm.h b/src/examples/Conway/LifeFarm.h similarity index 100% rename from src/tests/Conway/LifeFarm.h rename to src/examples/Conway/LifeFarm.h diff --git a/src/examples/Conway/Makefile b/src/examples/Conway/Makefile new file mode 100644 index 000000000..44fdd7112 --- /dev/null +++ b/src/examples/Conway/Makefile @@ -0,0 +1,87 @@ +# Makefile for Conway + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConway + +# Object files +ODIR = obj +_OBJ = LifeFarm.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConway.cpp b/src/examples/Conway/testConway.cpp similarity index 87% rename from src/tests/testConway.cpp rename to src/examples/Conway/testConway.cpp index f474bc1df..b434ba798 100644 --- a/src/tests/testConway.cpp +++ b/src/examples/Conway/testConway.cpp @@ -5,7 +5,7 @@ */ #include -#include "Conway/LifeFarm.h" +#include "LifeFarm.h" using namespace tsgl; @@ -41,6 +41,7 @@ using namespace tsgl; * \param can Reference to the Canvas to draw to. */ void conwayFunction(Canvas& can) { + Background * bg = can.getBackground(); const int IPF = 100, // Iterations per frame WW = can.getWindowWidth(), // Window width WH = can.getWindowHeight(); // Window height @@ -67,15 +68,15 @@ void conwayFunction(Canvas& can) { if(!paused) { for (int i = 0; i < IPF; i++) { if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + farm.addAnt(can.getMouseX() + WW/2, can.getMouseY() + WH/2); + bg->drawPixel(can.getMouseX(), can.getMouseY(), ColorInt(255,255,255,255)); } farm.moveAnts(); } } if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + farm.addAnt(can.getMouseX() + WW/2, can.getMouseY() + WH/2); + bg->drawPixel(can.getMouseX(), can.getMouseY(), ColorInt(255,255,255,255)); } } } @@ -84,7 +85,6 @@ void conwayFunction(Canvas& can) { int main(int argc, char* argv[]) { int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Conway's Game of Life"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Conway's Game of Life", BLACK); c.run(conwayFunction); } diff --git a/src/examples/CubeRun/Makefile b/src/examples/CubeRun/Makefile new file mode 100644 index 000000000..f7fa42ccd --- /dev/null +++ b/src/examples/CubeRun/Makefile @@ -0,0 +1,87 @@ +# Makefile for CubeRun + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCubeRun + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/CubeRun/testCubeRun.cpp b/src/examples/CubeRun/testCubeRun.cpp new file mode 100644 index 000000000..09e9424dc --- /dev/null +++ b/src/examples/CubeRun/testCubeRun.cpp @@ -0,0 +1,168 @@ +/* + * testCubeRun.cpp + * + * Usage: ./testCubeRun + */ + +#include +#include +#include +#define FONT "./assets/freefont/FreeSansBold.ttf" +#define zDelta 10 +#define obRoll 45.0 +#define OBJECT_Y -53.0 +#define PLAYER_MOVE_DIST 15.0 +#define numObstacles 20 +#define SIDE_LENGTH 25 +#define interObstacleDistance 600.0 + +using namespace tsgl; + +class ThreadData{ +private: + unsigned threadID; + Cube * myObstacle; + float myXDelta; + float myYDelta; + float myInitialZ; + +public: + ThreadData(unsigned tid, Cube* obstacle, float x, float z){ + threadID = tid; + myObstacle = obstacle; + myXDelta = x; + myInitialZ = z; + } + void moveObCloser(){ + myObstacle->changeXBy(myXDelta); + myObstacle->changeZBy(zDelta); + } + + void resetLocation(){ + myObstacle->setCenterX(0.0); + myObstacle->setCenterY(OBJECT_Y); + myObstacle->setCenterZ(myInitialZ); + } + + Cube * getObstacle(){ return myObstacle; } + + float getInitialZ(){ return myInitialZ; } +}; + +// Player cube +ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; +Cube * playerCube = new Cube(0.0, OBJECT_Y, 300, SIDE_LENGTH, 0.0, 0.0, 0.0, colors); + + +void increaseX() { + playerCube->changeXBy(PLAYER_MOVE_DIST); + // printf("X: %f\n", playerCube->getCenterX()); + if(playerCube->getCenterX() - SIDE_LENGTH/2.0 >= 135){ + playerCube->setCenterX(-135); + } +} + +void decreaseX() { + playerCube->changeXBy(-PLAYER_MOVE_DIST); + if(playerCube->getCenterX() + 12.5 <= -135){ + playerCube->setCenterX(135); + } +} + +float genXDelta(Cube * obstacle){ + float num = 0; + if(obstacle->getCenterZ() > -4000.0){ + num = (rand() % 101) / 100.0 - 0.5; // generate random number between -0.5 and 0.5 + } + else if(obstacle->getCenterZ() <= -4000.0){ + num = (rand() % 31) / 100.0 - 0.15; // generate random number between -0.15 and 0.15 + } + return num; +} + +// Main function to run animation and gameplay +void gameFunction(Canvas& can) { + srand( time(0) ); // initialize random seed + + ColorFloat colorArray[] = {RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, GRAY, WHITE}; + + // Initialize arrays to contain all obstacles and some obstacle data + Cube * obstacleArray[numObstacles]; + float initialZArray[numObstacles]; + float xDeltaArray[numObstacles]; + + // Fill arrays + for(unsigned i = 0; i < numObstacles; i++){ + obstacleArray[i] = new Cube(0.0, OBJECT_Y, (i+1.0)*(-interObstacleDistance), + SIDE_LENGTH, 0.0, 0.0, 0.0, colorArray[i%8]); + xDeltaArray[i] = genXDelta(obstacleArray[i]); + initialZArray[i] = obstacleArray[i]->getCenterZ(); + } + + // Create text object + unsigned scoreNum = 0; + Text * scoreText = new Text(265, 265, 0.0, std::to_wstring(scoreNum), FONT, 25, 0.0, 0.0, 0.0, WHITE); + + // Add objects to canvas + can.add(playerCube); + for(unsigned i = 0; i < numObstacles; i++){ + can.add(obstacleArray[i]); + } + can.add(scoreText); + + + // Initial key bindings + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, increaseX); + can.bindToButton(TSGL_LEFT, TSGL_PRESS, decreaseX); + + while (can.isOpen()){ + can.sleep(); + #pragma omp parallel + { + unsigned tid = omp_get_thread_num(); + unsigned numThreads = omp_get_num_threads(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < numObstacles; i ++){ + ThreadData * td = new ThreadData(tid, obstacleArray[i], xDeltaArray[i], initialZArray[i]); + + td->moveObCloser(); + + // Respawns obstacle at original starting point with a new xDelta + if(td->getObstacle()->getCenterZ() >= td->getInitialZ() + (numObstacles * interObstacleDistance) + 500.0){ + td->resetLocation(); + xDeltaArray[i] = genXDelta(td->getObstacle()); + } + // Lose conditions (if player cube collides with obstacle) + if(playerCube->getCenterZ() <= td->getObstacle()->getCenterZ() + SIDE_LENGTH and + playerCube->getCenterZ() >= td->getObstacle()->getCenterZ() - SIDE_LENGTH and + playerCube->getCenterX() <= td->getObstacle()->getCenterX() + SIDE_LENGTH and + playerCube->getCenterX() >= td->getObstacle()->getCenterX() - SIDE_LENGTH){ + can.close(); + } + } + } + + // Update score + scoreNum++; + scoreText->setText(std::to_wstring(scoreNum)); + } + + // Display final score + printf("\n*********************** \ + \nFinal score: %d \ + \n***********************\n", scoreNum); + + // Delete all objects + for(unsigned i = 0; i < numObstacles; i++){ + delete obstacleArray[i]; + } + delete scoreText; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 620, 620, "Cube Run", BLACK); + c.run(gameFunction); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Fork.h b/src/examples/DiningPhilosophers/Fork.h new file mode 100644 index 000000000..cffb1d9ad --- /dev/null +++ b/src/examples/DiningPhilosophers/Fork.h @@ -0,0 +1,53 @@ +/*! + * \struct Fork + * \brief Struct for the forks in the Dining Philosophers' problem + */ + +#ifndef FORK_H_ +#define FORK_H_ + +#include +using namespace tsgl; + +struct Fork { + int user, id; + ConcavePolygon * myShape; + Fork() { + user = -1; id = 0; + + const int POINTS = 20; // number of vertices in polygon + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; + + // scales (out of 100) for the dimensions of the fork + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; + + // create the fork points from the scale arrays + for(int i = 0; i < POINTS; ++i) { + // scale the fork + xs[i] = WIDTH * xscale[i]; + ys[i] = HEIGHT * yscale[i]; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; + } + + //Add vertices + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorFloat(1,1,1,1)); + } + void setCanvas( Canvas* can) { + can->add(myShape); + } + void draw(float x, float y, double angle, ColorFloat c) { + angle -= PI/2; + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); + } + ~Fork() { + delete myShape; + } +}; + +#endif /* FORK_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Makefile b/src/examples/DiningPhilosophers/Makefile new file mode 100644 index 000000000..55d687027 --- /dev/null +++ b/src/examples/DiningPhilosophers/Makefile @@ -0,0 +1,87 @@ +# Makefile for DiningPhilosophers + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = Fork.h philEnums.h \ + +# Main source file +TARGET = testPhilosophers + +# Object files +ODIR = obj +_OBJ = Philosopher.o Table.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/examples/DiningPhilosophers/Philosopher.cpp similarity index 85% rename from src/tests/DiningPhilosophers/Philosopher.cpp rename to src/examples/DiningPhilosophers/Philosopher.cpp index 5d58f8812..5775de58d 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/examples/DiningPhilosophers/Philosopher.cpp @@ -6,7 +6,7 @@ */ Philosopher::Philosopher() { setId(0,1); - myState = hasNone; + myState = thinking; myAction = doNothing; myCircle = NULL; numMeals = 0; @@ -19,10 +19,10 @@ Philosopher::~Philosopher() { /** * Adds Philosopher to Canvas or refreshes its color. */ -void Philosopher::draw(Canvas& can, int x, int y) { - const int SIZE = 32; +void Philosopher::draw(Canvas& can, float x, float y) { + const float SIZE = 45; if( !myCircle) { - myCircle = new Circle(x,y,SIZE,RED,BLACK); + myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorFloat(1,0,0,1)); can.add(myCircle); } } @@ -33,14 +33,14 @@ void Philosopher::draw(Canvas& can, int x, int y) { void Philosopher::refreshColor() { ColorFloat c; switch(myState) { - case hasNone: c=RED; break; + case hasNone: c=RED; break; case hasRight: c=ORANGE; break; case hasLeft: c=PURPLE; break; case hasBoth: c=GREEN; break; case isFull: c=BLUE; break; case thinking: c=BLUE; break; } - myCircle->setColor(c, BLACK); + myCircle->setColor(c); } /** @@ -95,7 +95,7 @@ bool Philosopher::release(Fork& f) { * Thinks and switches to hungry state if a random number is a multiple of 3. */ void Philosopher::think() { - if(rand()%3 == 0) { // 1/3 probability to go to hungry state + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state setState(hasNone); setAction(doNothing); } diff --git a/src/tests/DiningPhilosophers/Philosopher.h b/src/examples/DiningPhilosophers/Philosopher.h similarity index 97% rename from src/tests/DiningPhilosophers/Philosopher.h rename to src/examples/DiningPhilosophers/Philosopher.h index 2e1df70ed..bf27a1b59 100644 --- a/src/tests/DiningPhilosophers/Philosopher.h +++ b/src/examples/DiningPhilosophers/Philosopher.h @@ -25,7 +25,7 @@ class Philosopher { public: Philosopher(); ~Philosopher(); - void draw(Canvas& can, int x, int y); + void draw(Canvas& can, float x, float y); void refreshColor(); void addMeal(); bool acquire(Fork& f); diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/examples/DiningPhilosophers/Table.cpp similarity index 86% rename from src/tests/DiningPhilosophers/Table.cpp rename to src/examples/DiningPhilosophers/Table.cpp index 49a562815..5e9ca2666 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/examples/DiningPhilosophers/Table.cpp @@ -10,9 +10,8 @@ Table::Table(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - tabX = can.getWindowWidth()/2; - tabY = can.getWindowHeight()/2; - can.drawCircle(tabX,tabY,252,DARKGRAY); + Background * bg = can.getBackground(); + bg->drawCircle(0,0,0,175,0,0,0,ColorFloat(0.5,0.5,0.5,1)); phils = new Philosopher[numPhils]; forks = new Fork[numPhils]; for (int i = 0; i < numPhils; ++i) { @@ -22,41 +21,44 @@ Table::Table(Canvas& can, int p, PhilMethod m) { } float delta = 2.0f / numPhils * PI; for(int i = 0; i < numPhils; i++) { - myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); + bg->drawImage(120 * cos(i*delta), 140 * sin(i*delta), 0, "./assets/pics/spaghet.png", 100, 50, 0,0,0); } myMethod = m; switch(myMethod) { case forfeitWhenBlocked: - methodString = "forfeit when blocked"; + methodString = L"forfeit when blocked"; break; case waitWhenBlocked: - methodString = "wait when blocked"; + methodString = L"wait when blocked"; break; case nFrameRelease: - methodString = "release on nth frame"; + methodString = L"release on nth frame"; break; case resourceHierarchy: - methodString = "hierarchical resources"; + methodString = L"hierarchical resources"; break; case oddEven: - methodString = "odd-even check"; + methodString = L"odd-even check"; break; default: break; } - myCan2 = new Canvas(0,0,300,300,"Legend"); + myCan2 = new Canvas(0,0,300,300,"Legend", GRAY); myCan2->start(); - myCan2->drawText("Method:",16,32,32,BLACK); - myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); - myCan2->drawText("Legend:",16,96,24,BLACK); - myCan2->drawText("Red: Hungry",32,128,24,RED); - myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); - myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); - myCan2->drawText("Green: Eating",32,224,24,GREEN); - myCan2->drawText("Blue: Thinking",32,256,24,BLUE); - myCan2->drawText("Meals eaten: ",32,288,24,BROWN); - myCan2->drawCircle(165,281,3,BROWN); + Background * bg2 = myCan2->getBackground(); + + bg2->drawText(0,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); + bg2->drawText(0,96,0,L"\"" + methodString + L"\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + bg2->drawText(0,64,0,L"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + bg2->drawText(0,32,0,L"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); + bg2->drawText(0,0,0,L"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); + bg2->drawText(0,-32,0,L"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); + bg2->drawText(0,-64,0,L"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); + bg2->drawText(0,-96,0,L"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); + bg2->drawText(0,-121,0,L"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); + + bg2->drawRegularPolygon(65, -121,0,3,3,0,0,0, BROWN); } /*! @@ -65,10 +67,7 @@ Table::Table(Canvas& can, int p, PhilMethod m) { Table::~Table() { if (myCan2->isOpen()) myCan2->stop(); - else - myCan2->wait(); delete myCan2; - delete spaghetti; delete [] phils; delete [] forks; } @@ -421,7 +420,7 @@ void Table::checkStep() { * \brief Method for philosopher to act based on myAction. */ void Table::actStep() { - myCan2->sleep(); + // myCan2->sleep(); int i = omp_get_thread_num(); int left = i, right = (i+numPhils-1)%numPhils; switch(phils[i].action()) { @@ -454,27 +453,27 @@ void Table::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table::drawStep() { - const int RAD = 300; - int FORK_RAD = 250; + const float RAD = 225; + float FORK_RAD = 175; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; - const float BASEDIST = RAD+64; + const float BASEDIST = RAD+54; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; - ColorFloat fcolor = BLACK; + ColorFloat fcolor = ColorFloat(1,1,1,1); float fangle = (i+0.5f)*ARC; if( !phils[i].hasCircle() ) { - phils[i].draw(*myCan,tabX+RAD*cos(pangle),tabY+RAD*sin(pangle)); + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); } phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/RAD, dist = BASEDIST+8*(meals%10); - myCan->drawRegularPolygon(tabX+dist*cos(angle), tabY+dist*sin(angle), 3, 10 ,BROWN, BLACK); + float angle = pangle+(meals/10)*2*PI/(RAD), dist = BASEDIST+8*(meals%10); phils[i].addMeal(); + myCan->getBackground()->drawRegularPolygon(dist*cos(angle),dist*sin(angle),0,3,3,0,0,0,ColorFloat(0.5,0.3,0,1)); } if (forks[i].user == i) { fangle = i*ARC + CLOSE; @@ -484,8 +483,8 @@ void Table::drawStep() { fangle = ((i+1)*ARC) - CLOSE; fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; } else { - FORK_RAD = 220; + FORK_RAD = 140; fangle = pangle + PI / numPhils; } - forks[i].draw(tabX+FORK_RAD*cos(fangle),tabY+FORK_RAD*sin(fangle),fangle,fcolor); + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); } \ No newline at end of file diff --git a/src/tests/DiningPhilosophers/Table.h b/src/examples/DiningPhilosophers/Table.h similarity index 93% rename from src/tests/DiningPhilosophers/Table.h rename to src/examples/DiningPhilosophers/Table.h index c5c1c4401..4dde855bf 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/examples/DiningPhilosophers/Table.h @@ -22,14 +22,12 @@ using namespace tsgl; class Table { private: - int tabX, tabY, numPhils; + int numPhils; PhilMethod myMethod; - std::string methodString; + std::wstring methodString; Canvas *myCan, *myCan2; - Image * spaghetti; Philosopher *phils; Fork *forks; - TextureHandler loader; public: Table(Canvas& can, int p, PhilMethod m); diff --git a/src/tests/DiningPhilosophers/philEnums.h b/src/examples/DiningPhilosophers/philEnums.h similarity index 100% rename from src/tests/DiningPhilosophers/philEnums.h rename to src/examples/DiningPhilosophers/philEnums.h diff --git a/src/tests/testPhilosophers.cpp b/src/examples/DiningPhilosophers/testPhilosophers.cpp similarity index 92% rename from src/tests/testPhilosophers.cpp rename to src/examples/DiningPhilosophers/testPhilosophers.cpp index cbdbd41e1..0aa034717 100644 --- a/src/tests/testPhilosophers.cpp +++ b/src/examples/DiningPhilosophers/testPhilosophers.cpp @@ -26,8 +26,8 @@ #include #include #include -#include "DiningPhilosophers/Table.h" -#include "DiningPhilosophers/Philosopher.h" +#include "Table.h" +#include "Philosopher.h" using namespace tsgl; @@ -74,21 +74,21 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step } }); + #pragma omp parallel num_threads(philosophers) + { while(can.isOpen()) { - #pragma omp parallel num_threads(philosophers) - { + can.sleep(); if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { if(stepThrough) { philPauses[omp_get_thread_num()] = true; } t.checkStep(); can.pauseDrawing(); - if(method == forfeitWhenBlocked || method == waitWhenBlocked) { //Synchronize to see Livelock and Deadlock + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock #pragma omp barrier //Barrier for optional synchronization } t.actStep(); t.drawStep(); can.resumeDrawing(); } - can.sleep(); } } } @@ -102,6 +102,6 @@ int main(int argc, char* argv[]) { int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven - Canvas c(-1, -1, 1300, 1000, "Dining Philosophers",1.0f/speed); + Canvas c(-1, -1, Canvas::getDisplayWidth(), Canvas::getDisplayHeight(), "Dining Philosophers",1.0f/speed); c.run(philosopherFunction,nphil,resM,stepThrough); } diff --git a/src/examples/DiningPhilosophers3D/Fork3D.h b/src/examples/DiningPhilosophers3D/Fork3D.h new file mode 100644 index 000000000..6425a0a50 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Fork3D.h @@ -0,0 +1,53 @@ +/*! + * \struct Fork3D + * \brief Struct for the forks in the 3D visualization of the Dining Philosophers' problem + */ + +#ifndef FORK3D_H_ +#define FORK3D_H_ + +#include +using namespace tsgl; + +struct Fork3D { + int user, id; + ConcavePolygon * myShape; + Fork3D() { + user = -1; id = 0; + + const int POINTS = 20; // number of vertices in polygon + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; + + // scales (out of 100) for the dimensions of the 3D fork + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; + + // create the 3D fork points from the scale arrays + for(int i = 0; i < POINTS; ++i) { + // scale the 3D fork + xs[i] = WIDTH * xscale[i]; + ys[i] = HEIGHT * yscale[i]; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; + } + + //Add vertices + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,WHITE); + } + void setCanvas( Canvas* can) { + can->add(myShape); + } + void draw(float x, float y, double angle, ColorFloat c) { + angle -= PI/2; + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); + } + ~Fork3D() { + delete myShape; + } +}; + +#endif /* FORK3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Makefile b/src/examples/DiningPhilosophers3D/Makefile new file mode 100644 index 000000000..0295d80ec --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Makefile @@ -0,0 +1,87 @@ +# Makefile for DiningPhilosophers3D + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = Fork3D.h philEnums.h \ + +# Main source file +TARGET = test3DPhilosophers + +# Object files +ODIR = obj +_OBJ = Philosopher3D.o Table3D.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Philosopher3D.cpp b/src/examples/DiningPhilosophers3D/Philosopher3D.cpp new file mode 100644 index 000000000..b7e9c0b92 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Philosopher3D.cpp @@ -0,0 +1,120 @@ +#include "Philosopher3D.h" + +/*! + * \brief Explicitly constructs a new Philosopher3D. + * \details Explicit constructor for a new Philosopher3D object. + */ +Philosopher3D::Philosopher3D() { + setId(0,1); + myState = thinking; + myAction = doNothing; + myCylinder = NULL; + myCone = NULL; + numMeals = 0; +} + +Philosopher3D::~Philosopher3D() { + delete myCylinder; + delete myCone; + for (Pyramid * meal : meals) + { + delete meal; + } + meals.clear(); +} + +/** + * Adds Philosopher3D to Canvas or refreshes its color. + */ +void Philosopher3D::draw(Canvas& can, float x, float y) { + const float SIZE = 45; + if( !myCylinder) { + myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,RED); + can.add(myCylinder); + } + if( !myCone && myCylinder) { + myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorFloat(0.7,0,0,1)); + myCone->setRotationPoint(myCylinder->getCenterX(), myCylinder->getCenterY(), myCylinder->getCenterZ()); + can.add(myCone); + } +} + +/** + * Updates the Philosopher3D's color based on its state + */ +void Philosopher3D::refreshColor() { + ColorFloat c; + switch(myState) { + case hasNone: c=RED; break; + case hasRight: c=ORANGE; break; + case hasLeft: c=PURPLE; break; + case hasBoth: c=GREEN; break; + case isFull: c=BLUE; break; + case thinking: c=BLUE; break; + } + myCylinder->setColor(c); + myCone->setColor(ColorFloat(c.R*.7,c.G*.7,c.B*.7,c.A)); +} + +/** + * Adds a meal representation to meals and the Canvas + */ +void Philosopher3D::addMeal(float x, float y, float z) { + numMeals++; + meals.push_back(new Pyramid(x,y,z,3,8,4,0,0,90,ColorFloat(0.5,0.3,0,1))); +} + +Pyramid * Philosopher3D::getLastMeal() { + return meals.back(); +} + +/** + * Picks up a fork specified by its reference + */ +bool Philosopher3D::acquire(Fork3D& f) { + if (f.user >= 0) + return false; + if (f.id == myLeft) { + if (myState == hasNone) + myState = hasLeft; + else if (myState == hasRight) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + if (f.id == myRight) { + if (myState == hasNone) + myState = hasRight; + else if (myState == hasLeft) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + return false; +} + +/** + * Releases a fork specified by its reference + */ +bool Philosopher3D::release(Fork3D& f) { + if (f.user != id) + return false; + if (myState != isFull) + myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; + f.user = -1; + return true; +} + +/** + * Thinks and switches to hungry state if a random number is a multiple of 3. + */ +void Philosopher3D::think() { + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state + setState(hasNone); + setAction(doNothing); + } +} diff --git a/src/examples/DiningPhilosophers3D/Philosopher3D.h b/src/examples/DiningPhilosophers3D/Philosopher3D.h new file mode 100644 index 000000000..0781393c4 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Philosopher3D.h @@ -0,0 +1,83 @@ +/*! + * \class Philosopher3D + * \brief Object representing a 3D philosopher in the Dining Philosophers' problem + * \details The Philosopher3D class contains variables and methods necessary for + * representing a philosopher at a table. Each Philosopher3D may acquire or release + * the fork to his left or to his right (or both), with his state changing + * accordingly. + */ + +#ifndef PHILOSOPHER3D_H_ +#define PHILOSOPHER3D_H_ + +#include +#include +#include "Fork3D.h" +#include "philEnums.h" + +class Philosopher3D { +private: + PhilState myState; + PhilAction myAction; + int id, myLeft, myRight; + unsigned int numMeals; + Cylinder *myCylinder; + Cone * myCone; + std::vector meals; +public: + Philosopher3D(); + ~Philosopher3D(); + void draw(Canvas& can, float x, float y); + void refreshColor(); + void addMeal(float x, float y, float z); + Pyramid * getLastMeal(); + bool acquire(Fork3D& f); + bool release(Fork3D& f); + void think(); + + // Mutators + /*! + * \brief Resets the Philosopher3D to thinking after he eats. + */ + void eat() { myState = thinking; myAction = doNothing;} + /*! + * \brief Mutator for myState + * \param s PhilState to set myState to. + */ + void setState(PhilState s) { myState = s; } + /*! + * \brief Mutator for myAction + * \param s PhilAction to set myAction to. + */ + void setAction(PhilAction a) { myAction = a; } + /*! + * \brief Mutator for id + * \param i Which philosopher id to mutate + * \param nphil Total number of philosophers. + */ + void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } + + //Accessors + /** + * Accessor for number of meals Philosopher3D has consumed. + */ + int getMeals() { return numMeals; } + /** + * Accessor for Philosopher3D's state. + */ + PhilState state() { return myState; } + /** + * Accessor for Philosopher3D's action. + */ + PhilAction action() { return myAction; } + /** + * Accessor for Philosopher3D's id. + */ + int getId() { return id; } + /** + * Accessor for Philosopher3D's cylinder. + */ + bool hasCylinder() { return myCylinder; } +}; + +#endif /* PHILOSOPHER3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Table3D.cpp b/src/examples/DiningPhilosophers3D/Table3D.cpp new file mode 100644 index 000000000..1458c55ec --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Table3D.cpp @@ -0,0 +1,497 @@ +#include "Table3D.h" + +/*! + * \brief Creates a new 3D Table of dining Philosopher3Ds. + * \details Explicit constructor for a new Table3D object. + * \param can The Canvas on which the Table3D is to be drawn. + * \param p Integer denoting the number of Philosopher3Ds at the Table3D + * \param m PhilMethod denoting how the Philosopher3Ds should interact. + */ +Table3D::Table3D(Canvas& can, int p, PhilMethod m) { + numPhils = p; + myCan = &can; + myTable = new Cylinder(0,0,-55,100,150,0,0,90,ColorFloat(0.5,0.5,0.5,1)); + can.add(myTable); + phils = new Philosopher3D[numPhils]; + forks = new Fork3D[numPhils]; + for (int i = 0; i < numPhils; ++i) { + phils[i].setId(i,numPhils); + forks[i].id = i; + forks[i].setCanvas(myCan); + } + spaghettis = new Image*[numPhils](); + float delta = 2.0f / numPhils * PI; + for(int i = 0; i < numPhils; i++) { + spaghettis[i] = new Image(95 * cos(i*delta), 105 * sin(i*delta), -1, "./assets/pics/spaghet.png", 100, 50, 0,0,0); + can.add(spaghettis[i]); + } + myMethod = m; + switch(myMethod) { + case forfeitWhenBlocked: + methodString = L"forfeit when blocked"; + break; + case waitWhenBlocked: + methodString = L"wait when blocked"; + break; + case nFrameRelease: + methodString = L"release on nth frame"; + break; + case resourceHierarchy: + methodString = L"hierarchical resources"; + break; + case oddEven: + methodString = L"odd-even check"; + break; + default: + break; + } + + myCan2 = new Canvas(0,0,300,300,"Legend"); + myCan2->start(); + Background * bg2 = myCan2->getBackground(); + + bg2->drawText(0,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); + bg2->drawText(0,96,0,L"\"" + methodString + L"\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + bg2->drawText(0,64,0,L"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + bg2->drawText(0,32,0,L"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); + bg2->drawText(0,0,0,L"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); + bg2->drawText(0,-32,0,L"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); + bg2->drawText(0,-64,0,L"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); + bg2->drawText(0,-96,0,L"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); + bg2->drawText(0,-121,0,L"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); + + bg2->drawRegularPolygon(65, -121,0,3,3,0,0,0, BROWN); +} + +/*! + * \brief Destructor for Table3D. + */ +Table3D::~Table3D() { + if (myCan2->isOpen()) + myCan2->stop(); + delete myCan2; + for (int i = 0; i < numPhils; i++) + delete spaghettis[i]; + delete myTable; + delete [] phils; + delete [] forks; +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the id numbers for the left and the right Philsopher's state. + * - Switch for the state of a Philosopher3D: + * - Philosopher3D has no fork: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Deadlock amongst threads. + */ +void Table3D::forfeitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(releaseRight); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].setState(hasNone); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch for the state of the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Livelock amongst threads. + */ +void Table3D::waitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the right fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the left fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::nFrameReleaseMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseRight); + else + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states for the left and right Philosopher3Ds. + * - Switch statement for the state of the current Philosopher3D. + * - Philosopher3D has no forks: + * - If the right Philosopher3D's id is less than the left Philsopher's id: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Else, if the left fork is free then try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the right fork: + * - If the left fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::hierarchyMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (right < left) { + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + } else { + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the Philosopher3D's id is even + * - Philosopher3D has right fork (odd id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the left fork. + * - Else, release the right fork. + * . + * - Philosopher3D has left fork (even id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the right fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This method is the one that works best. + */ +void Table3D::oddEvenMethod(int id) { + switch(phils[id].state()) { + case hasNone: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryBoth); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(releaseRight); + } + break; + case hasLeft: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + +/*! + * \brief Method for determining which method of resolution the philosopher is using. + */ +void Table3D::checkStep() { + int i = omp_get_thread_num(); + if (phils[i].state() == isFull) { + phils[i].eat(); + return; + } + switch(myMethod) { + case forfeitWhenBlocked: + forfeitWhenBlockedMethod(i); + break; + case waitWhenBlocked: + waitWhenBlockedMethod(i); + break; + case nFrameRelease: + nFrameReleaseMethod(i); + break; + case resourceHierarchy: + hierarchyMethod(i); + break; + case oddEven: + oddEvenMethod(i); + break; + default: + break; + } +} + +/*! + * \brief Method for philosopher to act based on myAction. + */ +void Table3D::actStep() { + // myCan2->sleep(); + int i = omp_get_thread_num(); + int left = i, right = (i+numPhils-1)%numPhils; + switch(phils[i].action()) { + case tryLeft: + phils[i].acquire(forks[left]); + break; + case tryRight: + phils[i].acquire(forks[right]); + break; + case tryBoth: + phils[i].acquire(forks[left]); + phils[i].acquire(forks[right]); + break; + case releaseLeft: + phils[i].release(forks[left]); + break; + case releaseRight: + phils[i].release(forks[right]); + break; + case releaseBoth: + phils[i].release(forks[left]); + phils[i].release(forks[right]); + break; + default: + break; + } +} + +/*! + * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. + */ +void Table3D::drawStep() { + const float RAD = 195; + float FORK_RAD = 130; + const float ARC =2*PI/numPhils; + const float CLOSE = 0.15f; + const float BASEDIST = RAD+100; + + int i = omp_get_thread_num(); + float pangle = (i*2*PI)/numPhils; + ColorFloat fcolor = WHITE; + float fangle = (i+0.5f)*ARC; + + if( !phils[i].hasCylinder() ) { + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); + } + + phils[i].refreshColor(); + if( phils[i].state() == isFull ) { + int meals = phils[i].getMeals(); + float angle = pangle+(meals/10)*2*PI/(RAD), dist = BASEDIST+8*(meals%10); + phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); + Pyramid * p = phils[i].getLastMeal(); + p->setIsOutlined(false); + myCan->add(p); + } + if (forks[i].user == i) { + fangle = i*ARC + CLOSE; + fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; + } + else if((forks[i].user == (i+1)%numPhils)) { + fangle = ((i+1)*ARC) - CLOSE; + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; + } else { + FORK_RAD = 120; + fangle = pangle + PI / numPhils; + } + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Table3D.h b/src/examples/DiningPhilosophers3D/Table3D.h new file mode 100644 index 000000000..d690f90c4 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Table3D.h @@ -0,0 +1,55 @@ +/*! + * \class Table3D + * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. + * \details The Table3D class keeps track of the forks and philosophers in the Dining + * Philosophers' problem; it additionally manages the actions of the philosophers. + * \details Each step of the problem is broken up into two phases. In the checking phase, + * the philosophers look at the 3D table around them and, without communicating with the + * other philosophers, determine an action to take based on their state and the states + * of their adjacent forks. + * \details In the action phase, each philosopher attempts to execute the action previously + * determined in the checking phase. If unsuccessful, the philosopher does nothing; + * otherwise, the philosopher's state changes depending on the action taken. + */ + +#ifndef TABLE3D_H_ +#define TABLE3D_H_ + +#include +#include "Philosopher3D.h" + +using namespace tsgl; + +class Table3D { +private: + int numPhils; + PhilMethod myMethod; + std::wstring methodString; + Canvas *myCan, *myCan2; + Philosopher3D *phils; + Fork3D *forks; + Cylinder * myTable; + Image ** spaghettis; +public: + Table3D(Canvas& can, int p, PhilMethod m); + + ~Table3D(); + + void forfeitWhenBlockedMethod(int id); + + void waitWhenBlockedMethod(int id); + + void nFrameReleaseMethod(int id); + + void hierarchyMethod(int id); + + void oddEvenMethod(int id); + + void checkStep(); + + void actStep(); + + void drawStep(); +}; + +#endif /* TABLE3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/philEnums.h b/src/examples/DiningPhilosophers3D/philEnums.h new file mode 100644 index 000000000..17390208e --- /dev/null +++ b/src/examples/DiningPhilosophers3D/philEnums.h @@ -0,0 +1,22 @@ +#ifndef PHIL_ENUM_H_ +#define PHIL_ENUM_H_ + +/*! \brief Enum for valid states for the Dining Philosophers + */ +enum PhilState { + hasNone, hasRight, hasLeft, hasBoth, isFull, thinking +}; + +/*! \brief Enum for valid actions for the Dining Philosophers + */ +enum PhilAction { + doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth +}; + +/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem + */ +enum PhilMethod { + forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven +}; + +#endif /* PHIL_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp b/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp new file mode 100644 index 000000000..c2016a118 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp @@ -0,0 +1,107 @@ +/* + * test3DPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. + * This file includes a main method, Philospher3D class, Fork3D class, and Table3D class. + * + * The program provides a 3D visualization of the Dining Philosophers Problem + * in which philosophers sit around a table, think for a random amount of time, and then want to eat. + * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. + * This visualization includes six different ways of resolving the conflicts. + * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. + * + * Usage: ./test3DPhilosophers + * for enter: + * 'w' for waitWhenBlocked, which results in Deadlock + * 'f' for forfeitWhenBlocked, which results in Livelock + * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 + * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 + * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) + * + * for enter: + * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). + * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. + * + * If step-through is turned off, the spacebar pauses the visualization. + */ + +#include +#include +#include +#include "Table3D.h" +#include "Philosopher3D.h" + +using namespace tsgl; + +void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { + + PhilMethod method; + //switch statement to create table with resolution method + char resolutionMethod = RM[0]; + switch(resolutionMethod) { + case 'w': + method = waitWhenBlocked; //Deadlock + break; + case 'f': + method = forfeitWhenBlocked; //Livelock (when synchronized) + break; + case 'n': + method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 + break; + case 'r': + method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 + break; + case 'o': + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + default: + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + } + + Table3D t(can,philosophers,method); + + srand(time(NULL)); // seed the random number generator for thinking steps + + bool stepThrough = step; // Flag that determines whether the animation pauses between steps + bool paused = false; // Flag that determines whether the animation is paused + bool philPauses[philosophers]; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed + paused = !paused; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + }); + + #pragma omp parallel num_threads(philosophers) + { + while(can.isOpen()) { + can.sleep(); + if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { + if(stepThrough) { philPauses[omp_get_thread_num()] = true; } + t.checkStep(); + can.pauseDrawing(); + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock + #pragma omp barrier //Barrier for optional synchronization + } + t.actStep(); + t.drawStep(); + can.resumeDrawing(); + } + } + } +} + +int main(int argc, char* argv[]) { + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./test3DPhilosophers " + << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in tests/test3DPhilosophers.cpp" << std::endl; + } + int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 + int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 + bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); + std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven + Canvas c(-1, -1, Canvas::getDisplayWidth(), Canvas::getDisplayHeight(), "3D Dining Philosophers",1.0f/speed); + c.run(philosopherFunction,nphil,resM,stepThrough); +} diff --git a/src/tests/Fireworks/Arc.cpp b/src/examples/Fireworks/Arc.cpp similarity index 74% rename from src/tests/Fireworks/Arc.cpp rename to src/examples/Fireworks/Arc.cpp index 0c154288a..e96a9c623 100644 --- a/src/tests/Fireworks/Arc.cpp +++ b/src/examples/Fireworks/Arc.cpp @@ -15,10 +15,11 @@ Arc::Arc(Canvas& can) { f = NULL; myLife = 0; myCan = &can; - myX = rand() % myCan->getWindowWidth(); - myY = rand() % myCan->getWindowHeight(); - myAngle = ((rand() % 32000) / 32000.0f) * 2.0f*PI; - myRad = 20 + rand() % 180; + myBackground = myCan->getBackground(); + myX = saferand(-myCan->getWindowWidth()/2,myCan->getWindowWidth()/2); + myY = saferand(-myCan->getWindowHeight()/2,myCan->getWindowHeight()/2); + myAngle = (randfloat(32000)) * 2.0f*PI; + myRad = 20 + saferand(0,179); computeStepSize(); myColor = ColorHSV(0.0f,1.0f,1.0f,1.0f); } @@ -44,7 +45,7 @@ Arc::Arc(Canvas* can, int x, int y, int rad, float angle) { * \details Returns if myX and myY are between 0 and the Canvas' width and height respectively. */ bool Arc::outOfBounds() { - return (myX < 0 || myY < 0 || myX > myCan->getWindowWidth() || myY > myCan->getWindowHeight()); + return (myX < -myCan->getWindowWidth()/2 || myY < -myCan->getWindowHeight()/2 || myX > myCan->getWindowWidth()/2 || myY > myCan->getWindowHeight()/2); } /*! @@ -52,7 +53,7 @@ bool Arc::outOfBounds() { */ bool Arc::onBlackPixel() { const int LET = 14; - ColorInt col = myCan->getPoint(myX,myY); + ColorInt col = myCan->getBackground()->getPixel(myX,myY); return !(col.RgetWindowWidth(); - myY = rand() % myCan->getWindowHeight(); + myX = saferand(-myCan->getWindowWidth()/2,myCan->getWindowWidth()/2); + myY = saferand(-myCan->getWindowHeight()/2,myCan->getWindowHeight()/2); } computeStepSize(); } @@ -87,7 +88,7 @@ void Arc::relocate() { void Arc::step() { if (f != NULL) f->step(); - if (rand() % 100 < 2) { + if (saferand(0,99) < 2) { ++myRad; myStepSize = 1.0f/(myRad); } @@ -100,7 +101,7 @@ void Arc::step() { f = new Firework(*myCan,myX,myY); relocate(); } - myCan->drawPoint(myX,myY,myColor); + myBackground->drawPixel(myX,myY,myColor); } Arc::~Arc() { diff --git a/src/tests/Fireworks/Arc.h b/src/examples/Fireworks/Arc.h similarity index 94% rename from src/tests/Fireworks/Arc.h rename to src/examples/Fireworks/Arc.h index a7cd14718..474ea7a65 100644 --- a/src/tests/Fireworks/Arc.h +++ b/src/examples/Fireworks/Arc.h @@ -13,6 +13,7 @@ using namespace tsgl; class Arc { private: Canvas* myCan; + Background * myBackground; int myLife; float myX, myY, myRad; float myAngle, myStepSize; diff --git a/src/tests/Fireworks/Dot.cpp b/src/examples/Fireworks/Dot.cpp similarity index 82% rename from src/tests/Fireworks/Dot.cpp rename to src/examples/Fireworks/Dot.cpp index ccd6c5b37..2ac7e3cfa 100644 --- a/src/tests/Fireworks/Dot.cpp +++ b/src/examples/Fireworks/Dot.cpp @@ -16,6 +16,7 @@ */ Dot::Dot(Canvas& can, float x, float y, float s, float d, float f) { myCan = &can; + myBackground = myCan->getBackground(); dead = false; myX = x; myY = y; mySpeed = s; myDir = d; myFric = f; @@ -29,8 +30,8 @@ void Dot::step() { myX += mySpeed*cos(myDir); myY += mySpeed*sin(myDir); mySpeed *= myFric; - if (!dead) - myCan->drawPoint(myX,myY,WHITE); + if (!dead && abs(myX) < myCan->getWindowWidth() / 2 && abs(myY) < myCan->getWindowHeight() / 2) + myBackground->drawPixel(myX,myY,ColorInt(255,255,255,255)); if (mySpeed < 0.5f) dead = true; } diff --git a/src/tests/Fireworks/Dot.h b/src/examples/Fireworks/Dot.h similarity index 91% rename from src/tests/Fireworks/Dot.h rename to src/examples/Fireworks/Dot.h index 12052a7bf..94166d68e 100644 --- a/src/tests/Fireworks/Dot.h +++ b/src/examples/Fireworks/Dot.h @@ -13,6 +13,7 @@ class Dot { private: bool dead; Canvas* myCan; + Background * myBackground; float myX, myY, mySpeed, myDir, myFric; public: Dot(Canvas& can, float x, float y, float s, float d, float f); diff --git a/src/tests/Fireworks/Firework.cpp b/src/examples/Fireworks/Firework.cpp similarity index 91% rename from src/tests/Fireworks/Firework.cpp rename to src/examples/Fireworks/Firework.cpp index d222832a2..9ab5d9ed7 100644 --- a/src/tests/Fireworks/Firework.cpp +++ b/src/examples/Fireworks/Firework.cpp @@ -17,7 +17,7 @@ Firework::Firework(Canvas& can, int x, int y) { myX = x; myY = y; for (int i = 0; i < 10; ++i) { - myDots[i] = new Dot(can, myX,myY,(rand() % 10000)/10000.0f,(rand() % 10000)/10000.0f * 2 * PI, 0.99f); + myDots[i] = new Dot(can, myX,myY,randfloat(),randfloat() * 2 * PI, 0.99f); } } diff --git a/src/tests/Fireworks/Firework.h b/src/examples/Fireworks/Firework.h similarity index 100% rename from src/tests/Fireworks/Firework.h rename to src/examples/Fireworks/Firework.h diff --git a/src/examples/Fireworks/Makefile b/src/examples/Fireworks/Makefile new file mode 100644 index 000000000..a0add0510 --- /dev/null +++ b/src/examples/Fireworks/Makefile @@ -0,0 +1,87 @@ +# Makefile for Fireworks + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testFireworks + +# Object files +ODIR = obj +_OBJ = Arc.o Dot.o Firework.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testFireworks.cpp b/src/examples/Fireworks/testFireworks.cpp similarity index 71% rename from src/tests/testFireworks.cpp rename to src/examples/Fireworks/testFireworks.cpp index f62ba3ad0..e3499cb3a 100644 --- a/src/tests/testFireworks.cpp +++ b/src/examples/Fireworks/testFireworks.cpp @@ -5,7 +5,7 @@ */ #include -#include "Fireworks/Arc.h" +#include "Arc.h" using namespace tsgl; @@ -18,6 +18,7 @@ using namespace tsgl; * \param speed How fast the fireworks move. */ void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { + Background * bg = can.getBackground(); Arc** arcs = new Arc*[numFireworks]; for (int i = 0; i < numFireworks; i++) { arcs[i] = new Arc(can); @@ -25,19 +26,19 @@ void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { ColorFloat col = can.getBackgroundColor(); col.A = 0.04f; const int CWW = can.getWindowWidth(), CWH = can.getWindowHeight(); - while(can.isOpen()) { - #pragma omp parallel num_threads(threads) - { - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - for (int n = 0; n < speed; ++n) { - for (int i = tid; i < numFireworks; i += nthreads) - arcs[i]->step(); - if (tid == 0) - can.drawRectangle(0,0,CWW,CWH,col); - #pragma omp barrier - } - can.sleep(); + #pragma omp parallel num_threads(threads) + { + while(can.isOpen()) { + can.sleep(); + int tid = omp_get_thread_num(); + int nthreads = omp_get_num_threads(); + for (int n = 0; n < speed; ++n) { + for (int i = tid; i < numFireworks; i += nthreads) + arcs[i]->step(); + if (tid == 0) + bg->drawRectangle(0,0,0,CWW,CWH,0,0,0,col); + #pragma omp barrier + } } } for (int i = 0; i < numFireworks; i++) { @@ -54,8 +55,6 @@ int main(int argc, char* argv[]) { int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); int f = (argc > 4) ? atoi(argv[4]) : 50; int s = (argc > 5) ? atoi(argv[5]) : 10; - Canvas c(-1, -1, w, h, "Fireworks!"); - c.setBackgroundColor(BLACK); - c.start(); - fireworkFunction(c,t,f,s); + Canvas c(-1, -1, w, h, "Fireworks!", BLACK); + c.run(fireworkFunction,t,f,s); } diff --git a/src/examples/ForestFire/Makefile b/src/examples/ForestFire/Makefile new file mode 100644 index 000000000..853be5406 --- /dev/null +++ b/src/examples/ForestFire/Makefile @@ -0,0 +1,87 @@ +# Makefile for ForestFire + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testForestFire + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testForestFire.cpp b/src/examples/ForestFire/testForestFire.cpp similarity index 79% rename from src/tests/testForestFire.cpp rename to src/examples/ForestFire/testForestFire.cpp index 60a43ae24..0dbd758a4 100644 --- a/src/tests/testForestFire.cpp +++ b/src/examples/ForestFire/testForestFire.cpp @@ -8,10 +8,6 @@ using namespace tsgl; -float randfloat(int divisor = 10000) { - return (rand() % divisor) / (float) divisor; -} - /*! * \brief Pseudo-simulates a forest fire using a lot of probability and randomness. * \details @@ -41,12 +37,13 @@ float randfloat(int divisor = 10000) { * \param can Reference to the Canvas being drawn to. */ void forestFireFunction(Canvas& can) { + Background * bg = can.getBackground(); const int WINDOW_W = can.getWindowWidth(), // Set the screen sizes WINDOW_H = can.getWindowHeight(); const float LIFE = 10, STRENGTH = 0.03, MAXDIST = sqrt(WINDOW_W * WINDOW_W + WINDOW_H * WINDOW_H) / 2; - srand(time(NULL)); // Seed the random number generator + // srand(time(NULL)); // Seed the random number generator bool* onFire = new bool[WINDOW_W * WINDOW_H](); float* flammability = new float[WINDOW_W * WINDOW_H](); //Setting each pixel's flammablity @@ -57,21 +54,21 @@ void forestFireFunction(Canvas& can) { float tdist = (MAXDIST - sqrt(xi * xi + yi * yi)) / MAXDIST; float f = 0.01 + (i * j % 100) / 100.0 * randfloat(100) / 2 * tdist; flammability[i * WINDOW_H + j] = f; - can.drawPoint(i, j, ColorFloat(0.0f, f, 0.0f, 1.0f)); + bg->drawPixel(i - WINDOW_W/2, WINDOW_H/2 - j, ColorFloat(0.0f, f, 0.0f, 1.0f)); } } //"Lakes" for (int reps = 0; reps < 32; reps++) { - int x = rand() % WINDOW_W; - int y = rand() % WINDOW_H; - int w = rand() % (WINDOW_W - x); - int h = rand() % (WINDOW_H - y); + int x = saferand(-WINDOW_W/2, WINDOW_W/2); + int y = saferand(-WINDOW_H/2, WINDOW_H/2); + int w = saferand(0, WINDOW_W/2 - abs(x)) * 2; + int h = saferand(0, WINDOW_H/2 - abs(y)) * 2; if (w > 32) w = 32; if (h > 32) h = 32; - for (int i = 0; i < w; i++) { - for (int j = 0; j < h; j++) { - flammability[(x + i) * WINDOW_H + (y + j)] = 0.01; - can.drawPoint(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); + for (int i = -w/2; i < w/2; i++) { + for (int j = -h/2; j < h/2; j++) { + flammability[(x + i + WINDOW_W/2) * WINDOW_H + (y + j + WINDOW_H/2)] = 0.01; + bg->drawPixel(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); } } } @@ -86,11 +83,9 @@ void forestFireFunction(Canvas& can) { for (int j = 0; j < 2; j++) { firePoint fire = { WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, LIFE, STRENGTH }; fires.push(fire); - can.drawPoint(WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); + bg->drawPixel(0 - 1 + i, 0 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); } } - Rectangle *rec = new Rectangle(10,10,10,10,BLUE); - can.add(rec); while (can.isOpen()) { can.sleep(); int l = fires.size(); @@ -103,30 +98,29 @@ void forestFireFunction(Canvas& can) { firePoint fire = { f.x - 1, f.y, LIFE, f.strength }; fires.push(fire); onFire[myCell - WINDOW_H] = true; - can.drawPoint(f.x - 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2 - 1, f.y - WINDOW_H/2, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.x < WINDOW_W - 1 && !onFire[myCell + WINDOW_H] && randfloat() < flammability[myCell + WINDOW_H]) { firePoint fire = { f.x + 1, f.y, LIFE, f.strength }; fires.push(fire); onFire[myCell + WINDOW_H] = true; - can.drawPoint(f.x + 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2 + 1, f.y - WINDOW_H/2, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.y > 0 && !onFire[myCell - 1] && randfloat() < flammability[myCell - 1]) { firePoint fire = { f.x, f.y - 1, LIFE, f.strength }; fires.push(fire); onFire[myCell - 1] = true; - can.drawPoint(f.x, f.y - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2, f.y - WINDOW_H/2 - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.y < WINDOW_H && !onFire[myCell + 1] && randfloat() < flammability[myCell + 1]) { firePoint fire = { f.x, f.y + 1, LIFE, f.strength }; fires.push(fire); onFire[myCell + 1] = true; - can.drawPoint(f.x, f.y + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2, f.y - WINDOW_H/2 + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } } } - delete rec; delete[] onFire; delete[] flammability; } diff --git a/src/tests/Langton/AntFarm.cpp b/src/examples/Langton/AntFarm.cpp similarity index 67% rename from src/tests/Langton/AntFarm.cpp rename to src/examples/Langton/AntFarm.cpp index a2bfd5910..c4f41e91f 100644 --- a/src/tests/Langton/AntFarm.cpp +++ b/src/examples/Langton/AntFarm.cpp @@ -25,21 +25,23 @@ AntFarm::~AntFarm() { } void AntFarm::addAnt(int x, int y, int r, int g, int b, int d) { - if (size < cap) + if (size < cap) { ants[size] = new LangtonAnt(x, y, r, g, b, d, this); size++; + } } inline void AntFarm::moveAnt(int j) { - if (filled[ants[j]->myX + width * ants[j]->myY]) { + Background * bg = can->getBackground(); + if (filled[(ants[j]->myX + width/2) + width * (ants[j]->myY + height/2)]) { ants[j]->myDir = (ants[j]->myDir + 1) % 4; if (shading) - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); else - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); } else { ants[j]->myDir = (ants[j]->myDir + 3) % 4; - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); } } @@ -57,7 +59,7 @@ void AntFarm::moveAnts() { moveAnt(j); } for (int j = 0; j < size; j++) { - filled[ants[j]->myX + width * ants[j]->myY] ^= true; + filled[(ants[j]->myX + width/2) + width * (ants[j]->myY + height/2)] ^= true; ants[j]->move(); } } diff --git a/src/tests/Langton/AntFarm.h b/src/examples/Langton/AntFarm.h similarity index 100% rename from src/tests/Langton/AntFarm.h rename to src/examples/Langton/AntFarm.h diff --git a/src/tests/Langton/LangtonAnt.cpp b/src/examples/Langton/LangtonAnt.cpp similarity index 68% rename from src/tests/Langton/LangtonAnt.cpp rename to src/examples/Langton/LangtonAnt.cpp index 0d1621cf9..a70eee914 100644 --- a/src/tests/Langton/LangtonAnt.cpp +++ b/src/examples/Langton/LangtonAnt.cpp @@ -12,22 +12,22 @@ LangtonAnt::LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p) { myBlue = b; myDir = d; myFarm = p; - myAlpha = 16; + myAlpha = 48; } void LangtonAnt::move() { switch (myDir) { case UP: - myY = (myY > 0) ? myY - 1 : myFarm->height - 1; + myY = (myY < myFarm->height/2 - 1) ? myY + 1 : -myFarm->height/2; break; case RIGHT: - myX = (myX < myFarm->width - 1) ? myX + 1 : 0; + myX = (myX < myFarm->width/2 - 1) ? myX + 1 : -myFarm->width/2; break; case DOWN: - myY = (myY < myFarm->height - 1) ? myY + 1 : 0; + myY = (myY > -myFarm->height/2) ? myY - 1 : myFarm->height/2 - 1; break; case LEFT: - myX = (myX > 0) ? myX - 1 : myFarm->width - 1; + myX = (myX > -myFarm->width/2) ? myX - 1 : myFarm->width/2 - 1; break; default: break; diff --git a/src/tests/Langton/LangtonAnt.h b/src/examples/Langton/LangtonAnt.h similarity index 100% rename from src/tests/Langton/LangtonAnt.h rename to src/examples/Langton/LangtonAnt.h diff --git a/src/examples/Langton/Makefile b/src/examples/Langton/Makefile new file mode 100644 index 000000000..41682e16e --- /dev/null +++ b/src/examples/Langton/Makefile @@ -0,0 +1,87 @@ +# Makefile for Langton + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLangton + +# Object files +ODIR = obj +_OBJ = AntFarm.o LangtonAnt.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLangton.cpp b/src/examples/Langton/testLangton.cpp similarity index 86% rename from src/tests/testLangton.cpp rename to src/examples/Langton/testLangton.cpp index f954dcd9f..1d1d4f58d 100644 --- a/src/tests/testLangton.cpp +++ b/src/examples/Langton/testLangton.cpp @@ -7,7 +7,7 @@ #include #include -#include "Langton/AntFarm.h" +#include "AntFarm.h" using namespace tsgl; @@ -34,11 +34,13 @@ void alphaLangtonFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants bool paused = false; + Background * bg = can.getBackground(); + AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); Timer pulse(28.72 / 60); double time = pulse.getTime(); @@ -52,8 +54,8 @@ void alphaLangtonFunction(Canvas& can) { can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&paused]() { paused = !paused; }); - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg]() { + bg->clear(); }); while (can.isOpen()) { @@ -62,7 +64,7 @@ void alphaLangtonFunction(Canvas& can) { for (int i = 0; i < IPF; i++) farm.moveAnts(); if (pulse.pastPeriod()) - can.clearProcedural(); + bg->clear(); } } } @@ -88,7 +90,7 @@ void langtonFunction(Canvas& can) { WH = can.getWindowHeight(); // Window height AntFarm farm(WW,WH,4,&can); farm.setParallel(false); - farm.addAnt(WW / 2,WH / 2,MAX_COLOR,0,0,0); + farm.addAnt(0,0,MAX_COLOR,0,0,0); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class for (int i = 0; i < IPF; i++) { @@ -114,10 +116,10 @@ void langtonColonyFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); farm.setShading(true); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class @@ -138,13 +140,13 @@ void langtonRainbowFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); farm.setShading(true); for (int j = 0; j < 4; j++) - farm.ants[j]->setAlpha(64); + farm.ants[j]->setAlpha(64*3); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class @@ -163,8 +165,7 @@ int main(int argc, char* argv[]) { w = h = 960; //If not, set the width and height to a default value //Alpha Langton std::cout << "Alpha Langton's Ant" << std::endl; - Canvas c1(-1, -1, w, h, "Langton's Ant w/Alpha (enter to pause)"); - c1.setBackgroundColor(BLACK); + Canvas c1(-1, -1, w, h, "Langton's Ant w/Alpha (enter to pause)", BLACK); c1.run(alphaLangtonFunction); //Regular Langton @@ -179,7 +180,6 @@ int main(int argc, char* argv[]) { //Colorful Langton std::cout << "Dynamically Colored Langton's Ants" << std::endl; - Canvas c4(-1, -1, w, h, "Colorful Langton's Ants"); - c4.setBackgroundColor(BLACK); + Canvas c4(-1, -1, w, h, "Colorful Langton's Ants", BLACK); c4.run(langtonRainbowFunction); } diff --git a/src/examples/Makefile b/src/examples/Makefile new file mode 100644 index 000000000..52665f64c --- /dev/null +++ b/src/examples/Makefile @@ -0,0 +1,51 @@ +# Master Makefile for Examples + +# ***************************************************** + +# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the examples +SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ + ArrayShakerSort/. \ + Ballroom/. \ + Clock/. \ + Conway/. \ + CubeRun/. \ + DiningPhilosophers/. \ + DiningPhilosophers3D/. \ + Fireworks/. \ + ForestFire/. \ + Langton/. \ + Mandelbrot/. \ + MergeSort/. \ + NewtonPendulum/. \ + Pandemic/. \ + Pong/. \ + ProducerConsumer/. \ + ReaderWriter/. \ + SeaUrchin/. \ + ShakerSort/. \ + SolarSystem/. \ + ThreadedArrayAddition/. \ + ThreadedArrayBubbleSort/. \ + ThreadedArrayOperations/. \ + ThreadedSolarSystem/. \ + Voronoi/. \ + +SUBDIRS_TO_CLEAN := $(subst /.,..., $(SUBDIRS_TO_BUILD)) # Used to clean the examples + + +all: $(SUBDIRS_TO_BUILD) + +$(SUBDIRS_TO_BUILD): + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" + @tput sgr0; + @echo "" + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) + +clean: $(SUBDIRS_TO_CLEAN) + +$(SUBDIRS_TO_CLEAN): + cd $(subst ...,,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/tests/Mandelbrot/Buddhabrot.cpp b/src/examples/Mandelbrot/Buddhabrot.cpp similarity index 92% rename from src/tests/Mandelbrot/Buddhabrot.cpp rename to src/examples/Mandelbrot/Buddhabrot.cpp index f3d2ab888..c38a80777 100644 --- a/src/tests/Mandelbrot/Buddhabrot.cpp +++ b/src/examples/Mandelbrot/Buddhabrot.cpp @@ -21,6 +21,7 @@ Buddhabrot::~Buddhabrot() { } void Buddhabrot::draw(Cart& can) { + CartesianBackground * cart = can.getBackground(); cww = can.getWindowWidth(), cwh = can.getWindowHeight(); const unsigned long MAXITS = cww*cwh*10; ColorFloat tcolor(1.0f,1.0f,1.0f,0.1f); @@ -30,7 +31,7 @@ void Buddhabrot::draw(Cart& can) { counter[i] = new int[cww]; while (myRedraw) { myRedraw = false; - can.clearProcedural(); + cart->clear(); for (int i = 0; i < cwh; ++i) for (int j = 0; j < cww; ++j) counter[i][j] = 0; @@ -71,7 +72,7 @@ void Buddhabrot::draw(Cart& can) { int boxX = (znums[its].real()-cMinx)/cpw; #pragma omp atomic ++(counter[boxY][boxX]); - can.Canvas::drawPixel(boxY, boxX, tcolor); + cart->Background::drawPixel(boxX - cww/2, cwh/2 - boxY, tcolor); } } #pragma omp atomic @@ -99,7 +100,7 @@ void Buddhabrot::draw(Cart& can) { for (int i = omp_get_thread_num(); i < cwh; i += omp_get_num_threads()) for (int j = 0; j < cww; ++j) { float normalize = sqrt((float)counter[i][j]/maxIts); - can.Canvas::drawPixel(i, j, (ColorFloat)can.getPixel(i,j) * normalize); + cart->Background::drawPixel(j - cww/2, cwh/2 - i, (ColorFloat)cart->Background::getPixel(j - cww/2,cwh/2 - i) * normalize); } } while (can.isOpen() && !myRedraw) diff --git a/src/tests/Mandelbrot/Buddhabrot.h b/src/examples/Mandelbrot/Buddhabrot.h similarity index 100% rename from src/tests/Mandelbrot/Buddhabrot.h rename to src/examples/Mandelbrot/Buddhabrot.h diff --git a/src/tests/Mandelbrot/GradientMandelbrot.cpp b/src/examples/Mandelbrot/GradientMandelbrot.cpp similarity index 89% rename from src/tests/Mandelbrot/GradientMandelbrot.cpp rename to src/examples/Mandelbrot/GradientMandelbrot.cpp index c2cba1c51..3645952eb 100644 --- a/src/tests/Mandelbrot/GradientMandelbrot.cpp +++ b/src/examples/Mandelbrot/GradientMandelbrot.cpp @@ -7,6 +7,7 @@ GradientMandelbrot::GradientMandelbrot(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} void GradientMandelbrot::draw(Cart& can) { + CartesianBackground * cart = can.getBackground(); while (myRedraw) { myRedraw = false; #pragma omp parallel num_threads(myThreads) @@ -29,7 +30,8 @@ void GradientMandelbrot::draw(Cart& can) { } smooth /= (myDepth + 1); float value = (float)iterations/myDepth; - can.drawPoint(col, row, ColorHSV((float)smooth * 6.0f, 1.0f, value, 1.0f)); + if (row < cart->getMaxY()) + cart->drawPixel(col, row, ColorHSV((float)smooth * 6.0f, 1.0f, value, 1.0f)); if (myRedraw) break; } can.handleIO(); diff --git a/src/tests/Mandelbrot/GradientMandelbrot.h b/src/examples/Mandelbrot/GradientMandelbrot.h similarity index 100% rename from src/tests/Mandelbrot/GradientMandelbrot.h rename to src/examples/Mandelbrot/GradientMandelbrot.h diff --git a/src/tests/Mandelbrot/Julia.cpp b/src/examples/Mandelbrot/Julia.cpp similarity index 82% rename from src/tests/Mandelbrot/Julia.cpp rename to src/examples/Mandelbrot/Julia.cpp index 1e84b90f2..a43675ce9 100644 --- a/src/tests/Mandelbrot/Julia.cpp +++ b/src/examples/Mandelbrot/Julia.cpp @@ -7,6 +7,7 @@ Julia::Julia(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} void Julia::draw(Cart& can) { + CartesianBackground * cart = can.getBackground(); const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas VisualTaskQueue vq(CH); while(myRedraw) { @@ -16,7 +17,9 @@ void Julia::draw(Cart& can) { vq.reset(); #pragma omp parallel num_threads(myThreads) { - vq.showLegend(); + if (omp_get_thread_num() == 0) // showLegend creates a Canvas, which should ONLY be done by thread 0 + vq.showLegend(); + #pragma omp barrier int myNext; while(true) { // As long as we aren't trying to render off of the screen... #pragma omp critical @@ -36,10 +39,10 @@ void Julia::draw(Cart& can) { c = c * c + z; } if(iterations == myDepth) { // If the point never escaped, draw it black - can.drawPoint(col, row, BLACK); + cart->drawPixel(col, row, ColorInt(0,0,0,255)); } else { // Otherwise, draw it with color based on how long it took float mult = iterations/(float)myDepth; - can.drawPoint(col, row, Colors::blend(BLACK,WHITE,0.25f+0.5f*mult)*mult); + cart->drawPixel(col, row, Colors::blend(BLACK,WHITE,0.25f+0.5f*mult)*mult); } if (!can.isOpen() || myRedraw) break; } @@ -56,4 +59,5 @@ void Julia::draw(Cart& can) { } } vq.close(); + can.close(); } diff --git a/src/tests/Mandelbrot/Julia.h b/src/examples/Mandelbrot/Julia.h similarity index 100% rename from src/tests/Mandelbrot/Julia.h rename to src/examples/Mandelbrot/Julia.h diff --git a/src/examples/Mandelbrot/Makefile b/src/examples/Mandelbrot/Makefile new file mode 100644 index 000000000..6d1496939 --- /dev/null +++ b/src/examples/Mandelbrot/Makefile @@ -0,0 +1,87 @@ +# Makefile for Mandelbrot + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMandelbrot + +# Object files +ODIR = obj +_OBJ = Buddhabrot.o GradientMandelbrot.o Julia.o Mandelbrot.o Nova.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/Mandelbrot/Mandelbrot.cpp b/src/examples/Mandelbrot/Mandelbrot.cpp similarity index 67% rename from src/tests/Mandelbrot/Mandelbrot.cpp rename to src/examples/Mandelbrot/Mandelbrot.cpp index 5e3986600..2ba2451af 100644 --- a/src/tests/Mandelbrot/Mandelbrot.cpp +++ b/src/examples/Mandelbrot/Mandelbrot.cpp @@ -12,16 +12,18 @@ Mandelbrot::Mandelbrot(unsigned threads, unsigned depth) { } void Mandelbrot::manhattanShading(CartesianCanvas& can) { - int** canPoints = new int*[can.getWindowHeight()]; - for (int i = 0; i < can.getWindowHeight(); ++i) { - canPoints[i] = new int[can.getWindowWidth()]; - for (int j = 0; j < can.getWindowWidth(); ++j) { - ColorInt c = can.getPoint(j,i); + int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + CartesianBackground * bg = can.getBackground(); + int** canPoints = new int*[cwh]; + for (int i = 0; i < cwh; ++i) { + canPoints[i] = new int[cww]; + for (int j = 0; j < cww; ++j) { + ColorInt c = bg->Background::getPixel(j - cww/2,i - cwh/2); canPoints[i][j] = ((c.R == c.G) && (c.G == c.B) && (c.B == 0)) ? 0 : -1; } } bool done = false; - int loop, cwh = can.getWindowHeight(), cww = can.getWindowWidth(); + int loop; for (loop = 0; !done; ++loop) { done = true; #pragma omp parallel for @@ -51,8 +53,8 @@ void Mandelbrot::manhattanShading(CartesianCanvas& can) { for (int i = 0; i < cwh; ++i) { for (int j = 0; j < cww; ++j) { float mult = sqrt(avg*((float)canPoints[i][j])/loop); - ColorFloat c = can.getPoint(j,i); - can.Canvas::drawPoint(j,i,c*mult); + ColorFloat c = bg->Background::getPixel(j - cww/2,i - cwh/2); + bg->Background::drawPixel(j - cww/2,i - cwh/2,c*mult); } } @@ -63,50 +65,68 @@ void Mandelbrot::manhattanShading(CartesianCanvas& can) { } void Mandelbrot::bindings(Cart& can) { + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&can, this]() { + can.zoom(can.getMouseX(), can.getMouseY(), 0.5); + can.getBackground()->clear(); + this->myRedraw = true; + }); can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can, this]() { - can.clearProcedural(); + can.getBackground()->clear(); this->myRedraw = true; }); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&can, this]() { - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->myFirstX, this->myFirstY); + this->myFirstX = can.getMouseX(); + this->myFirstY = can.getMouseY(); }); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&can, this]() { - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->mySecondX, this->mySecondY); + this->mySecondX = can.getMouseX(); + this->mySecondY = can.getMouseY(); if (!(this->myFirstX == this->mySecondX || this->myFirstY == this->mySecondY)) { can.zoom(this->myFirstX, this->myFirstY, this->mySecondX, this->mySecondY); + can.getBackground()->clear(); this->myRedraw = true; } }); can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&can, this]() { Decimal x, y; - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); + x = can.getMouseX(); + y = can.getMouseY(); can.zoom(x, y, 1.5); + can.getBackground()->clear(); this->myRedraw = true; }); can.bindToScroll([&can, this](double dx, double dy) { Decimal x, y; - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); + x = can.getMouseX(); + y = can.getMouseY(); Decimal scale; if (dy == 1) scale = .5; else scale = 1.5; can.zoom(x, y, scale); + can.getBackground()->clear(); this->myRedraw = true; }); } void Mandelbrot::draw(Cart& can) { + CartesianBackground * bg = can.getBackground(); const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas const int XBRD = 10; //Border for out progress bar const int YBRD = 40; //Border for out progress bar const int PBWIDTH = 800; Canvas pCan(0, 0, PBWIDTH, 100, "Thread Workloads"); //Canvas for our progress bar + Background * pBack = pCan.getBackground(); pCan.start(); - ProgressBar pb( - XBRD,YBRD,pCan.getWindowWidth()-XBRD*2,pCan.getWindowHeight()-YBRD*2, - 0,CH - (CH % myThreads),myThreads //Make the max PB value a multiple of myThreads + ProgressBar * pb = new ProgressBar( + 0,0,0, + pCan.getWindowWidth()-XBRD*2,pCan.getWindowHeight()-YBRD*2, + 0,CH - (CH % myThreads),myThreads, 0,0,0 //Make the max PB value a multiple of myThreads ); + pCan.add(pb); + for (int i = 0; i < myThreads; ++i) { - pCan.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); + float w = pb->getWidth(); + pBack->drawText(-w/2 + i*w/myThreads + 10, pb->getHeight()+8, 0, std::to_wstring(i), "./assets/freefont/FreeSerif.ttf", 32, 0,0,0, BLACK); } while(myRedraw) { myRedraw = false; @@ -118,29 +138,26 @@ void Mandelbrot::draw(Cart& can) { ColorFloat tcolor = Colors::highContrastColor(tid); double blocksize = can.getCartHeight() / nthreads; double blockheight = CH / nthreads; - pb.update(blockheight*tid); - pCan.drawProgress(&pb); + pb->update(blockheight*tid); long double startrow = blocksize * tid + can.getMinY(); for(unsigned int k = 0; k <= blockheight && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... - pb.update(k+(CH*tid)/nthreads); - //Messy, but effective -// pCan.drawRectangle(XBRD,YBRD,pCan.getWindowWidth()-XBRD,pCan.getWindowHeight()-YBRD,pCan.getBackgroundColor(),true); - //Elegant, but flickery - pCan.drawProgress(&pb); - long double row = startrow + can.getPixelHeight() * k; - for(long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { - complex originalComplex(col, row); - complex c(col, row); + pb->update(k+(CH*tid)/nthreads); + long double y = startrow + can.getPixelHeight() * k; + for(long double x = bg->getMinX(); x <= bg->getMaxX(); x += can.getPixelWidth()) { + complex originalComplex(x, y); + complex c(x, y); unsigned iterations = 0; while (std::abs(c) < 2.0 && iterations != myDepth) { // Compute it until it escapes or we give up iterations++; c = c * c + originalComplex; } if(iterations == myDepth) { // If the point never escaped, draw it black - can.drawPoint(col, row, BLACK); + if (y < can.getMaxY()) + bg->drawPixel(x, y, ColorFloat(0,0,0,1)); } else { // Otherwise, draw it with color based on how long it took float mult = iterations/(float)myDepth; - can.drawPoint(col, row, Colors::blend(tcolor,WHITE,0.25f+0.5f*mult)*mult); + if (y < can.getMaxY()) + bg->drawPixel(x, y, Colors::blend(tcolor,WHITE,0.25f+0.5f*mult)*mult); } if (myRedraw) break; } @@ -158,4 +175,5 @@ void Mandelbrot::draw(Cart& can) { if (pCan.isOpen()) pCan.close(); pCan.wait(); //Close our progress bar if we're done + delete pb; } diff --git a/src/tests/Mandelbrot/Mandelbrot.h b/src/examples/Mandelbrot/Mandelbrot.h similarity index 100% rename from src/tests/Mandelbrot/Mandelbrot.h rename to src/examples/Mandelbrot/Mandelbrot.h diff --git a/src/tests/Mandelbrot/Nova.cpp b/src/examples/Mandelbrot/Nova.cpp similarity index 82% rename from src/tests/Mandelbrot/Nova.cpp rename to src/examples/Mandelbrot/Nova.cpp index 983438694..9245a2f21 100644 --- a/src/tests/Mandelbrot/Nova.cpp +++ b/src/examples/Mandelbrot/Nova.cpp @@ -7,6 +7,7 @@ Nova::Nova(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} void Nova::draw(Cart& can) { + CartesianBackground * cart = can.getBackground(); const long double R = 1.0l; while (myRedraw) { myRedraw= false; @@ -37,10 +38,14 @@ void Nova::draw(Cart& can) { smooth = 0; smooth = smooth - (int)smooth; //float mult = iterations/(float)myDepth; - if (iterations == myDepth) - can.drawPoint(col, row, BLACK); - else - can.drawPoint(col, row, ColorHSV((float) smooth * 6.0f, 1.0f, (float) smooth, 1.0f)); + if (row <= can.getMaxY()) { + if (iterations == myDepth) { + cart->drawPixel(col, row, ColorInt(0,0,0,255)); + } + else { + cart->drawPixel(col, row, ColorHSV((float) smooth * 6.0f, 1.0f, (float) smooth, 1.0f)); + } + } } can.handleIO(); if (myRedraw) break; diff --git a/src/tests/Mandelbrot/Nova.h b/src/examples/Mandelbrot/Nova.h similarity index 100% rename from src/tests/Mandelbrot/Nova.h rename to src/examples/Mandelbrot/Nova.h diff --git a/src/tests/testMandelbrot.cpp b/src/examples/Mandelbrot/testMandelbrot.cpp similarity index 95% rename from src/tests/testMandelbrot.cpp rename to src/examples/Mandelbrot/testMandelbrot.cpp index 91172986d..fc5c048e7 100644 --- a/src/tests/testMandelbrot.cpp +++ b/src/examples/Mandelbrot/testMandelbrot.cpp @@ -6,11 +6,11 @@ /*testMandelbrot.cpp contains multiple functions that display a Mandelbrot set in similar fashions (and one that displays a Julia set). */ -#include "Mandelbrot/Buddhabrot.h" -#include "Mandelbrot/Mandelbrot.h" -#include "Mandelbrot/GradientMandelbrot.h" -#include "Mandelbrot/Julia.h" -#include "Mandelbrot/Nova.h" +#include "Buddhabrot.h" +#include "Mandelbrot.h" +#include "GradientMandelbrot.h" +#include "Julia.h" +#include "Nova.h" using namespace tsgl; @@ -197,28 +197,27 @@ int main(int argc, char* argv[]) { unsigned d3 = (argc > 4) ? atoi(argv[4]) : 1000; //Buddhabrot & Julia //Normal Mandelbrot std::cout << "Normal Mandelbrot" << std::endl; - Cart c1(-1, -1, w, h, -2, -1.125, 1, 1.125, "Mandelbrot", FRAME / 2); + Cart c1(-1, -1, w, h, -2, -1.125, 1, 1.125, "Mandelbrot", GRAY, FRAME / 2); c1.run(mandelbrotFunction,t,d); //Gradient Mandelbrot std::cout << "Gradient Mandelbrot" << std::endl; - Cart c2(-1, -1, w, h, -2, -1.125, 1, 1.125, "Gradient Mandelbrot", FRAME / 2); + Cart c2(-1, -1, w, h, -2, -1.125, 1, 1.125, "Gradient Mandelbrot", GRAY, FRAME / 2); c2.run(gradientMandelbrotFunction,t,d2); - std::cout << "Buddhabrot" << std::endl; //Buddhabrot - Cart c3(-1, -1, w, h, -2, -1.125, 1, 1.125, "Buddhabrot", FRAME / 2); - c3.setBackgroundColor(BLACK); + std::cout << "Buddhabrot" << std::endl; + Cart c3(-1, -1, w, h, -2, -1.125, 1, 1.125, "Buddhabrot", BLACK, FRAME / 2); c3.run(buddhabrotFunction,t,d3); - //Julia #FIXME requires a different library path - std::cout << "Julia set" << std::endl; - Cart c4(x, -1, w2, h2, -2, -1.125, 1, 1.125, "Julia Set", FRAME / 2); - c4.run(juliaFunction,t,d3); - //Nova std::cout << "Nova" << std::endl; - Cart c5(x, -1, w, h, -1.0, -0.5, 0, 0.5, "Nova (Newton Fractal)", FRAME / 2); - c5.zoom(-0.361883,-0.217078,0.1f); + Cart c5(x, -1, w, h, -1.0, -0.5, 0, 0.5, "Nova (Newton Fractal)", GRAY, FRAME / 2); + c5.zoom(-0.361883,-0.217078,0.10f); c5.run(novaFunction,t,32); + + //Julia + std::cout << "Julia set" << std::endl; + Cart c4(x, -1, w2, h2, -2, -1.125, 1, 1.125, "Julia Set", GRAY, FRAME / 2); + c4.run(juliaFunction,t,d3); } diff --git a/src/examples/MergeSort/Makefile b/src/examples/MergeSort/Makefile new file mode 100644 index 000000000..be6834bef --- /dev/null +++ b/src/examples/MergeSort/Makefile @@ -0,0 +1,87 @@ +# Makefile for MergeSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMergeSort + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/MergeSort/testMergeSort.cpp b/src/examples/MergeSort/testMergeSort.cpp new file mode 100644 index 000000000..5bb67f9e7 --- /dev/null +++ b/src/examples/MergeSort/testMergeSort.cpp @@ -0,0 +1,204 @@ +/* + * testMergeSort.cpp + * + * Usage: ./testMergeSort + */ + +#include +#include + +using namespace tsgl; + +enum MergeState { + S_MERGE = 1, + S_SHIFT = 2, + S_WAIT = 3, + S_DONE = 4, + S_HIDE = 5 +}; + +struct sortData { + ColorFloat color; //Color of the thread + MergeState state; //Current state of the threads + int first, last, //Start and end of our block + left, right, //Indices of two numbers to compare + fi, hi, li, //Indices of first middle and last numbers in a set + depth; //Current depth of the merge + float* a; //Array of numbers to sort + int seg, segs; //Current / total segments + int size; + + sortData(float* arr, int f, int l, ColorFloat c) { + fi = hi = li = 0; //Initialize indices + left = right = 0; //Initialize bounds + color = c; //Set the color + a = arr; //Get a pointer to the array we'll be sorting + first = f; //Set the first element we need to worry about + last = l; //Set the last element we need to worry about + depth = 0; //We start at depth 0 + seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment + while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done + ++depth; //Otherwise, increment the depth... + segs *= 2; //...and double the number of segments + } + state = S_SHIFT; //Start Merging + size = 2; + } + + void restart(int l) { + depth = 0; + hi = last; + right = hi+1; + last = li = l; + fi = left = first; + state = S_MERGE; + size *= 2; + } + + void sortStep() { + float tmp; + int pivot, jump; + switch(state) { + case S_SHIFT: + pivot = jump = segs/2; + fi = first; li = last; + hi = (fi + li) / 2; //Set our half index to the median of our first and last + for (tmp = depth; tmp > 0; --tmp) { + jump /= 2; + if (seg < pivot) { + pivot -= jump; + li = hi; //Set out last index to our old half index + } else { + pivot += jump; + fi = hi+1; //Set out first index to our old half index plus one + } + hi = (fi + li) / 2; //Set our new half index to the median of our first and last + } + left = fi; right = hi+1; + state = S_MERGE; //We're ready to start Merging + break; + case S_MERGE: + if (left > right || right > last) { + seg = 0; //Reset our segment(s) + segs /= 2; //We're now using half as many segments + state = (depth-- == 0) ? S_WAIT : S_SHIFT; + } else if (right > li) { + ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices + } else if (left <= hi && a[left] < a[right]) { + ++left; + } else { + tmp = a[right]; + for (int x = right; x > left; --x) + a[x] = a[x-1]; + a[left] = tmp; + ++left; ++right; ++hi; + } + break; + default: + break; + } + } +}; + +/*! + * \brief Visualization of the bottom-up mergesort algorithm. + * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. + * \details Uses lines to represent the items being sorted. + * \details At the start, the items being sorted are all divided. + * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. + * \details Different colors represent different sections being sorted. + * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. + */ +void mergeSortFunction(Canvas& can, int threads, int size) { + const int IPF = 1; // Iterations per frame + float* numbers = new float[size]; // Array to store the data + Rectangle** rectangles = new Rectangle*[size]; // Array to store the data + float start = -can.getWindowWidth() * .45; + float width = can.getWindowWidth() * .9 / size; + for (int i = 0; i < size; i++) { + numbers[i] = saferand(1,can.getWindowHeight()); + rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); + rectangles[i]->setIsOutlined(false); + can.add(rectangles[i]); + } + + int baseNumVals = size / threads; + int extraVals = size % threads; + sortData** sd = new sortData*[threads]; + int firstIndex = 0; + int lastIndex = (extraVals == 0) ? baseNumVals-1 : baseNumVals; + for (int i = 0; i < threads; ++i) { + sd[i] = new sortData(numbers,firstIndex,lastIndex,Colors::highContrastColor(i)); + firstIndex = lastIndex+1; + if (i < extraVals-1) lastIndex += (baseNumVals + 1); + else lastIndex += baseNumVals; + } + while (can.isOpen()) { + #pragma omp parallel num_threads(threads) + { + int tid = omp_get_thread_num(); + can.sleep(); + if (sd[tid]->state == S_WAIT) { //Merge waiting threads + if ((tid % sd[tid]->size) > 0) + sd[tid]->state = S_DONE; + else { + int next = tid+sd[tid]->size/2; + if (next < threads && sd[next]->state == S_DONE) { + sd[next]->state = S_HIDE; + sd[tid]->restart(sd[next]->last); + } + } + } + for (int i = 0; i < IPF; i++) + sd[tid]->sortStep(); + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + float height; + ColorFloat color; + if (sd[tid]->state != S_HIDE) { + //Draw a black rectangle over our portion of the screen to cover up the old drawing + // can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); + for (int i = sd[tid]->first; i <= sd[tid]->last; ++i, ++start) { + height = numbers[i]; + if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) + color = WHITE; + else { + if (i == sd[tid]->right || i == sd[tid]->left) + color = WHITE; + else if (i < sd[tid]->left) + color = sd[tid]->color; + else if (i >= sd[tid]->fi && i <= sd[tid]->li) + color = Colors::blend(sd[tid]->color, WHITE, 0.5f); + else + color = Colors::blend(sd[tid]->color, BLACK, 0.5f); + } + rectangles[i]->setHeight(height); + rectangles[i]->setColor(color); + } + } + can.resumeDrawing(); //Tell the Canvas it can resume updating + } + } + for (int i = 0; i < threads; ++i) + delete sd[i]; + delete [] sd; + delete [] numbers; + for (int i = 0; i < size; i++) { + delete rectangles[i]; + } + delete [] rectangles; +} + +//Takes in command line arguments for the window width and height +//as well as for the number of threads to use +int main(int argc, char* argv[]) { + int s = (argc > 1) ? atoi(argv[1]) : 1024; + if (s < 10) s = 10; + int w = s * 1.3; + int h = w/2; + + int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); + for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 + + Canvas c(0, 0, w, h, "Bottom-up Merge Sort", BLACK); + c.run(mergeSortFunction, threads, s); +} diff --git a/src/examples/NewtonPendulum/Makefile b/src/examples/NewtonPendulum/Makefile new file mode 100644 index 000000000..adbdf159f --- /dev/null +++ b/src/examples/NewtonPendulum/Makefile @@ -0,0 +1,87 @@ +# Makefile for NewtonPendulum + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testNewtonPendulum + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testNewtonPendulum.cpp b/src/examples/NewtonPendulum/testNewtonPendulum.cpp similarity index 69% rename from src/tests/testNewtonPendulum.cpp rename to src/examples/NewtonPendulum/testNewtonPendulum.cpp index 6c4446778..2ed14fbe5 100644 --- a/src/tests/testNewtonPendulum.cpp +++ b/src/examples/NewtonPendulum/testNewtonPendulum.cpp @@ -38,25 +38,29 @@ void newtonPendulumFunction(Canvas& can, int numberOfBalls) { TOPSPEED = 9.0f, //Starting speed of balls AMP = 100; //Inverse amplitude of balls - //Automatic variables - const int WINDOW_W = can.getWindowWidth(), - WINDOW_H = can.getWindowHeight(), - CX = WINDOW_W / 2, //Center of window - CY = WINDOW_H / 2; - const float LINELEN = CY, + const float LINELEN = can.getWindowHeight() / 2, OFFSET = RADIUS*(BALLS-1); - for (float i = -(BALLS/2)+1; i < BALLS/2; ++i) { - can.drawLine(CX + RADIUS*2*i, 0, CX + RADIUS*2*i, LINELEN, BLACK); - can.drawCircle(CX + RADIUS*2*i, CY, RADIUS, GRAY, WHITE); + Line ** lines = new Line*[BALLS - 2]; + Circle ** balls = new Circle*[BALLS - 2]; + for (int i = -(BALLS/2)+1; i < BALLS/2; ++i) { + lines[i + BALLS/2 - 1] = new Line(RADIUS*2*i,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + can.add(lines[i + BALLS/2 - 1]); + balls[i + BALLS/2 - 1] = new Circle(RADIUS*2*i,0,0, RADIUS, 0,0,0,GRAY); + can.add(balls[i + BALLS/2 - 1]); } //Add moving Shapes - Circle* leftCircle = new Circle(CX - OFFSET, LINELEN, RADIUS, GRAY, WHITE); - Circle* rightCircle = new Circle(CX + OFFSET, LINELEN, RADIUS, GRAY, WHITE); - Line* leftLine = new Line(CX - OFFSET, 0, CX - OFFSET, LINELEN, BLACK); - Line* rightLine = new Line(CX + OFFSET, 0, CX + OFFSET, LINELEN, BLACK); - can.add(rightLine); can.add(leftLine); can.add(leftCircle); can.add(rightCircle); + Circle* leftCircle = new Circle(-OFFSET,0,0, RADIUS, 0,0,0,GRAY); + leftCircle->setRotationPoint(-OFFSET, LINELEN, 0); + Circle* rightCircle = new Circle(OFFSET,0,0, RADIUS, 0,0,0,GRAY); + rightCircle->setRotationPoint(OFFSET, LINELEN, 0); + Line* leftLine = new Line(-OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + leftLine->setRotationPoint(-OFFSET, LINELEN, 0); + Line* rightLine = new Line(OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + rightLine->setRotationPoint(OFFSET, LINELEN, 0); + can.add(rightLine); can.add(leftLine); + can.add(leftCircle); can.add(rightCircle); //Computation float rightPos = 0, leftPos = 0; //Initial positions of the edge balls @@ -88,26 +92,25 @@ void newtonPendulumFunction(Canvas& can, int numberOfBalls) { //Move the lines and balls! //Left - leftLine->setSecondEnd(CX - OFFSET + LINELEN*sin(leftPos/AMP), LINELEN*cos(leftPos/AMP)); - leftCircle->setCenter(CX - OFFSET + LINELEN*sin(leftPos/AMP), LINELEN*cos(leftPos/AMP)); + leftLine->setYaw(leftPos/AMP * 180 / PI - 90); + leftCircle->setYaw(leftPos/AMP * 180 / PI); //Right - rightLine->setSecondEnd(CX + OFFSET + LINELEN*sin(rightPos/AMP), LINELEN*cos(rightPos/AMP)); - rightCircle->setCenter(CX + OFFSET + LINELEN*sin(rightPos/AMP), LINELEN*cos(rightPos/AMP)); + rightLine->setYaw(rightPos/AMP * 180 / PI - 90); + rightCircle->setYaw(rightPos/AMP * 180 / PI); } delete leftCircle; delete rightCircle; delete leftLine; delete rightLine; + for (int i = 0; i < BALLS - 2; i++) { + delete balls[i]; + delete lines[i]; + } + delete [] balls; + delete [] lines; } -// saving this if we ever get procedural stuff working -// //Draw stationary lines and balls -// for (float i = -(BALLS/2)+1; i < BALLS/2; ++i) { -// can.drawLine(CX + RADIUS*2*i, 0, CX + RADIUS*2*i, LINELEN); -// can.drawCircle(CX + RADIUS*2*i, CY, RADIUS, GRAY, true); -// } - //Takes command line arguments for the width and height of the screen //as well as for the number of balls int main(int argc, char * argv[]) { @@ -125,7 +128,6 @@ int main(int argc, char * argv[]) { } else if(numberOfBalls % 2 == 0) { //If even, add 1 numberOfBalls++; } - Canvas c(-1, -1, w, h, "Newton's Pendulum"); - c.setBackgroundColor(WHITE); + Canvas c(-1, -1, w, h, "Newton's Pendulum", WHITE); c.run(newtonPendulumFunction,numberOfBalls); } diff --git a/src/examples/Pandemic/Makefile b/src/examples/Pandemic/Makefile new file mode 100644 index 000000000..02400f61b --- /dev/null +++ b/src/examples/Pandemic/Makefile @@ -0,0 +1,87 @@ +# Makefile for Pandemic + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = statusEnums.h + +# Main source file +TARGET = testPandemic + +# Object files +ODIR = obj +_OBJ = Person.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Pandemic/Person.cpp b/src/examples/Pandemic/Person.cpp new file mode 100644 index 000000000..89bf2365b --- /dev/null +++ b/src/examples/Pandemic/Person.cpp @@ -0,0 +1,255 @@ +#include "Person.h" + +using namespace tsgl; + +/*! + * \brief Default constructor for Person. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +Person::Person(){ + // location + myX = 0; + myY = 0; + // radius + myCircleRadius = 5; + myInfectionRadius = 35; + hasInfectionRadius = false; + // infection data + myStatus = susceptible; + numInfectedNearby = 0; + numDaysInfected = 0; + isToDie = false; + myNumDaysTillDead = 0; + + // Create visual representation of person + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, ColorFloat(1,1,0,1)); // yellow + // if hasInfectionRadius is set to true, create visual representation of infection radius + if(hasInfectionRadius){ + ColorFloat infectionRadiusColor = ColorFloat(0,0,0,0); + if(myStatus == infected){ + infectionRadiusColor = ColorFloat(1,0.5,0,0.5); + } + myInfectionCircle = new Circle(myX, myY, 0.0, myInfectionRadius-myCircleRadius, // ensures that only a small part of + // a person needs to be in the visible + // radius to be at risk of infection + 0.0, 0.0, 0.0, infectionRadiusColor); + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + } +} + +/*! + * \brief Explicitly constructs a new Person. + * \details This is the constructor for the Person class. + * \param x The x coordinate of the center of the Person. + * \param y The y coordinate of the center of the Person. + * \param radius The radius of the circle visually representing the Person. + * \param infectionRadius The radius of the circle representing the Person's + * infection radius. + * \param status The health status of the Person. + * \param showInfectionRadius Determines whether or not the infection radius is shown + * around the Person. + * \return A new Person with the specified coordinates, radius, and status. + */ +Person::Person(float x, float y, GLfloat radius, float infectionRadius, char status, bool showInfectionRadius){ + // location + myX = x; + myY = y; + // radius + myCircleRadius = radius; + myInfectionRadius = infectionRadius; + hasInfectionRadius = showInfectionRadius; + // infection data + myStatus = status; + numInfectedNearby = 0; + numDaysInfected = 0; + isToDie = false; + myNumDaysTillDead = 0; + + // Determine color + switch(myStatus){ + case susceptible : + myColor = ColorFloat(1,1,0,1); // yellow + break; + case infected : + myColor = ColorFloat(1,0,0,1); // red + break; + case immune : + myColor = ColorFloat(0,1,0,1); // green + break; + case dead : + myColor = ColorFloat(0.5,0.5,0.5,1); // grey + break; + default: + myColor = ColorFloat(0,0,0,1); // black + } + + // Create visual representation of person + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); + // if hasInfectionRadius is set to true, create visual representation of infection radius + if(hasInfectionRadius){ + ColorFloat infectionRadiusColor = ColorFloat(0,0,0,0); + if(myStatus == infected){ + infectionRadiusColor = ColorFloat(1,0.5,0,0.5); + } + myInfectionCircle = new Circle(myX, myY, 0.0, myInfectionRadius-myCircleRadius, // ensures that only a small part of + // a person needs to be in the visible + // radius to be at risk of infection + 0.0, 0.0, 0.0, infectionRadiusColor); + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + } +} + +/** + * \brief Adds the Person to the canvas. + * \param can The Canvas on which the Person is to be drawn. + */ +void Person::draw(Canvas& can){ + if(hasInfectionRadius){ + if(myStatus == infected){ + can.add(myInfectionCircle); + } + } + can.add(myCircle); +} + +/** + * \brief Changes the status of a Person. + * \param status The new status of the Person. + */ +void Person::setStatus(char status){ + myStatus = status; +} + +/** + * \brief Sets the color of the Person to a new color. + * \param c The new color. + */ +void Person::setColor(ColorFloat c){ + myCircle->setColor(c); +} + +/** + * \brief Changes the Person's x and y within certain bounds to simulate movement. + * \param x The value to add to the Person's current x-coordinate. + * \param y The value to add to the Person's current y-coordinate. + * \param max_x The upper bound of the x-coordinate. + * \param max_y The upper bound of the y-coordinate. + */ +void Person::moveBy(float x, float y, float max_x, float max_y){ + // Check if move is valid (within the window) + if((myX + x > -max_x) && (myX + x < max_x) && + (myY + y > -max_y) && (myY + y < max_y)) { + // Move Person + myCircle->changeXBy(x); myCircle->changeYBy(y); + if(hasInfectionRadius){ + myInfectionCircle->changeXBy(x); myInfectionCircle->changeYBy(y); + } + // Update info + myX += x; myY += y; + } +} + +/** + * \brief Checks if the Person's x and y is within the infection radius of another Person. + * \param personVec The vector containing all Person instances. + * \return true if the Person is within another's infection radius, false otherwise. + */ +bool Person::checkIfInfectedNearby(std::vector personVec){ + unsigned distance; + for(unsigned i = 0; i < personVec.size(); ++i){ + // Search for all people who are infected + if(personVec[i]->getStatus() == infected){ + // Check if susceptible person is in infection radius + distance = sqrt( pow(myX - personVec[i]->getX(), 2) + pow(myY - personVec[i]->getY(), 2) ); + if(distance < personVec[i]->getInfectionRadius() + myCircleRadius) + { + ++numInfectedNearby; + return true; + } + } + } + return false; +} + +/** + * \brief Changes the Person's status to infected if there is 1 or more infected Persons + * nearby and if the random number passed to the function is less than or equal to + * the contagious factor. + * \param can The Canvas on which the infection circle is to be drawn (if the Person becomes infected). + * \param contagiousFactor The probability of a Person getting infected. + * \param randNum The random number that determines whether or not the Person becomes infected. + * \return true if the Person has become infected, false otherwise. + */ +bool Person::determineIfInfected(Canvas& can, int contagiousFactor, int randNum){ + if(numInfectedNearby >= 1 && randNum <= contagiousFactor){ + myStatus = infected; + myCircle->setColor(ColorFloat(1,0,0,1)); // red + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(1,0.5,0,0.5)); // orange + can.add(myInfectionCircle); + } + numInfectedNearby = 0; + return true; + } + return false; +} + +/** + * \brief Determines whether or not a Person is to die from the infection. + * \param deadlinessFactor The probability of a Person dying. + * \param randNum The random number that determines whether or not the Person dies. + * \param daysTillDead The pre-determined number of days until the Person dies. + */ +void Person::determineIsToDie(int deadlinessFactor, int randNum, int daysTillDead){ + // Determine if person will die + if(randNum <= deadlinessFactor){ + isToDie = true; + // Determine number of days until person will die + myNumDaysTillDead = daysTillDead; + } +} + +/** + * \brief "Kills" a Person; sets the Person's status to dead, removes the Person's infection circle, and + * changes the Person's color to gray. + * \param can The Canvas on which the Person and the Person's infection circle are changed. + */ +void Person::die(Canvas& can){ + myStatus = dead; + myCircle->setColor(ColorFloat(0.5,0.5,0.5,1)); // grey + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(0,0,0,0)); // make circle transparent to ensure it isn't visible + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + can.remove(myInfectionCircle); + // hasInfectionRadius = false; + numInfectedNearby = 0; + } +} + +/** + * \brief "Recovers" a Person; sets the Person's status to immune, removes the Person's infection circle, and + * changes the Person's color to green. + * \param can The Canvas on which the Person and the Person's infection circle are changed. + */ +void Person::recover(Canvas& can){ + myStatus = immune; + myCircle->setColor(ColorFloat(0,1,0,1)); // green + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(0,0,0,0)); // make circle transparent to ensure it isn't visible + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + can.remove(myInfectionCircle); + // hasInfectionRadius = false; + numInfectedNearby = 0; + } +} + +/*! + * \brief Destructor for Person. + */ +Person::~Person(){ + delete myCircle; + if(hasInfectionRadius){ + delete myInfectionCircle; + } +} \ No newline at end of file diff --git a/src/examples/Pandemic/Person.h b/src/examples/Pandemic/Person.h new file mode 100644 index 000000000..341baf0e6 --- /dev/null +++ b/src/examples/Pandemic/Person.h @@ -0,0 +1,86 @@ +#ifndef PERSON_H_ +#define PERSON_H_ + +#include +#include +#include +#include "Circle.h" +#include "statusEnums.h" + +using namespace tsgl; + +class Person { +protected: + // location + float myX, myY; + // radius + GLfloat myCircleRadius; + float myInfectionRadius; + bool hasInfectionRadius; + // TSGL shapes/objects + Circle* myCircle; + Circle* myInfectionCircle; + ColorFloat myColor; + // infection data + char myStatus; + int numInfectedNearby; + int numDaysInfected; + bool isToDie; + int myNumDaysTillDead; +public: + // Constructors // + + Person(); + + Person(float x, float y, GLfloat radius, float infectionRadius, char status, bool hasInfectedRadius); + + // Draw // + + void draw(Canvas& can); + + // Accessors // + + GLfloat getCircleRadius() { return myCircleRadius; } + + float getInfectionRadius() { return myInfectionRadius; } + + Circle * getCircle() { return myCircle; } + + float getX() { return myX; } + + float getY() { return myY; } + + char getStatus() { return myStatus; } + + int getNumDaysInfected() { return numDaysInfected; } + + bool willDie() { return isToDie; } + + int getNumDaysTillDead() { return myNumDaysTillDead; } + + // Mutators // + + void setStatus(char status); + + void setColor(ColorFloat c); + + void moveBy(float x, float y, float max_x, float max_y); + + // Checking/updating functions // + + bool checkIfInfectedNearby(std::vector personVec); + + void increaseNumDaysInfected() { numDaysInfected += 1; } + + bool determineIfInfected(Canvas& can, int contagiousFactor, int randNum); + + void determineIsToDie(int deadlinessFactor, int randNum, int daysTillDead); + + void die(Canvas& can); + + void recover(Canvas& can); + + virtual ~Person(); +}; + +#endif /* PERSON_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/statusEnums.h b/src/examples/Pandemic/statusEnums.h new file mode 100644 index 000000000..4381e5859 --- /dev/null +++ b/src/examples/Pandemic/statusEnums.h @@ -0,0 +1,11 @@ +#ifndef STATUS_ENUM_H_ +#define STATUS_ENUM_H_ + +#include + +/*! \brief Enum for valid Person states for the Pandemic + */ +enum PersonState { + infected = 'v', immune = 'i', susceptible = 's', dead = 'd' +}; +#endif /* STATUS_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/testPandemic.cpp b/src/examples/Pandemic/testPandemic.cpp new file mode 100644 index 000000000..8b022d4d5 --- /dev/null +++ b/src/examples/Pandemic/testPandemic.cpp @@ -0,0 +1,348 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [contagiousFactor] + 1 <= numPersons <= 200, defaults to 50 + 0 <= contagiousFactor <= 100, defaults to 50 + */ + +#include +#include +#include +#include +#include "Person.h" +#include + +// disease constants +#define PERSON_RADIUS 5 // the size of each person on screen +// text constants +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 20 // font size for all text +#define TEXT_COLOR ColorFloat(0.2,1,1,1) // color for all text (light blue) + +using namespace tsgl; + +// To parse command line for custom program options +cxxopts::ParseResult parse(int argc, char* argv[]) { + try { + cxxopts::Options options("./src/examples/ParallelPandemic/testPandemic", "- command line options"); + + options.positional_help("[optional args]").show_positional_help(); + + options.allow_unrecognised_options().add_options() + ("h, help", "Print help") + ("n, num", "the number of people in the model", cxxopts::value()->default_value("100")) + ("i, initial", "the number of initially infected people (1-n)", cxxopts::value()->default_value("1")) + ("R, person-radius", "the radius of each person (1-30)", cxxopts::value()->default_value("5.0")) + ("t, sick-for", "the duration of the disease (in days)", cxxopts::value()->default_value("21")) + ("c, contagiousness" , "the contagiousness factor of the disease (0-100)", cxxopts::value()->default_value("50")) + ("r, infect-radius", "the infection radius of the disease (1-200)", cxxopts::value()->default_value("35")) + ("m, mortality", "the mortality factor of the disease (0-100)", cxxopts::value()->default_value("2")) + ("s, show-radius", "include to display the infection radius around each person", + cxxopts::value()->default_value("false")) + ("a, attendance", "include to print out the thread attendance (to see if all threads are running)", + cxxopts::value()->default_value("false")); + + auto results = options.parse(argc, argv); + + if(results.count("help") || results.count("h")){ + std::cout << options.help({"", "Group"}) << std::endl; + std::cout << "Use the up and down arrow keys to increase or decrease the animation speed, respectively." << std::endl; + exit(0); + } + + return results; + + } catch (const cxxopts::OptionSpecException& e) { + std::cout << "error parsing options: " << e.what() << std::endl; + exit(1); + } +} + +void pandemicFunction(Canvas& can, int argc, char* argv[]) { + // INITIALIZE VARIABLES // + int numPersons = 100; + float personRadius = 5.0; + float infectionRadius = 35; + bool showInfectionRadius; + bool takeAttendance; + // time + int numDays = 0; + int sickDuration = 21; + // counters + int num_initially_infected = 1; + int num_currently_infected; + int num_susceptible; + // pandemic factors + int contagiousFactor = 50; + int mortalityFactor = 2; + // ending stats/counters + int total_num_infections; + int total_num_infection_attempts = 0; + int total_num_deaths = 0; + // int total_num_death_attempts = 0; + int total_num_recoveries = 0; + float true_contagiousness = 0.0; + float true_mortality = 0.0; + float avgInfectionLength; + // Parse command line + auto result = parse(argc, argv); + + // SET OPTIONS // + if (result["num"].as() > 0) { + numPersons = result["num"].as(); + } + if (result["initial"].as() > 0 and result["initial"].as() <= numPersons) { + num_initially_infected = result["initial"].as(); + } + if (result["person-radius"].as() > 0.0 and result["person-radius"].as() <= 30) { + personRadius = result["person-radius"].as(); + } + if (result["sick-for"].as() > 0) { + sickDuration = result["sick-for"].as(); + } + if (result["contagiousness"].as() >= 0 and result["contagiousness"].as() <= 100) { + contagiousFactor = result["contagiousness"].as(); + } + if (result["infect-radius"].as() > 0 and result["infect-radius"].as() <= 200) { + infectionRadius = result["infect-radius"].as(); + } + if (result["mortality"].as() >= 0 and result["mortality"].as() <= 100) { + mortalityFactor = result["mortality"].as(); + } + + // boolean switches + showInfectionRadius = result["show-radius"].as(); + takeAttendance = result["attendance"].as(); + + // counters + num_currently_infected = num_initially_infected; + num_susceptible = numPersons - num_initially_infected; + total_num_infections = num_initially_infected; + total_num_infection_attempts = num_initially_infected; + // movement bounds + float max_x = can.getWindowWidth()/2 - personRadius; + float max_y = can.getWindowHeight()/2 - personRadius - FONT_SIZE; + + // random number generator, seed, and distributions + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine generator(seed); + std::uniform_int_distribution init_x_distr(-max_x, max_x); + std::uniform_int_distribution init_y_distr(-max_y, max_y); + std::uniform_int_distribution move_distr(-20, 20); + std::uniform_int_distribution sick_distr(1, sickDuration); + std::uniform_int_distribution chance_distr(1, 100); + + // Create arrays + std::vector personVec; + std::vector threadAttendance; + + // Insert infected into array + for(int i = 0; i < num_initially_infected; ++i){ + personVec.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + personRadius, infectionRadius, infected, showInfectionRadius)); + personVec[i]->draw(can); + } + // Determine if the initially infected will die + #pragma omp parallel num_threads(num_initially_infected) + { + int id = omp_get_thread_num(); + personVec[id]->determineIsToDie(mortalityFactor, chance_distr(generator), sick_distr(generator)); + } + + // Insert susceptible into array + for(int i = num_initially_infected; i < numPersons; ++i){ + personVec.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + personRadius, infectionRadius, susceptible, showInfectionRadius)); + personVec[i]->draw(can); + } + + // Set up thread "attendance sheet" + for(int i = 0; i < numPersons; ++i){ + threadAttendance.push_back(-1); + } + + // Create background + Background * bg = can.getBackground(); + + // Create text to display the current day + Text * dayText = new Text(0, 300, 0, L"Day 1", FONT, FONT_SIZE, 0, 0, 0, TEXT_COLOR); + can.add(dayText); + + float sleepTime = 0.5; // initial number of seconds to sleep + + // KEY BINDINGS // -> to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 1){ + sleepTime *= 2; + } + }); + + // OUTPUT INITIAL INFORMATION // + printf("\n***********************\ + \n* Initial information *\ + \n***********************\ + \n\ + \nInfection radius: %.1f\ + \nChance of infection: %d%%\ + \nChance of death: %d%%\ + \n\ + \nStarting number of people infected: %d\ + \nTotal number of people: %d\ + \n\n", infectionRadius, contagiousFactor, mortalityFactor, + num_initially_infected, numPersons); + + bool complete = false; // ensures simulation only runs once + bool printInfo = true; // ensures information is only printed once + + // RUN SIMULATION // + while (can.isOpen()) { + if(!complete){ + // Runs until there are no more infections + while(num_currently_infected != 0){ + // Increment number of days for pandemic + ++numDays; + // Update day number + dayText->setText(L"Day " + std::to_wstring(numDays)); + can.sleepFor(sleepTime); + + //------------------------------------- Parallel Block ------------------------------------------ + #pragma omp parallel num_threads(numPersons) + { + int id = omp_get_thread_num(); + + // Ensure there is one thread running per person (take attendance for threads) + if(numDays == 1){ + threadAttendance[id] = id; + } + + // No actions apply to people who are dead + if(personVec[id]->getStatus() != dead){ + // Move people + personVec[id]->moveBy(move_distr(generator), move_distr(generator), max_x, max_y); + // #ifdef _WIN32 + // can.sleepFor(sleepTime); + // #elif __CYGWIN__ + // can.sleepFor(sleepTime); + + // INFECTED + if(personVec[id]->getStatus() == infected){ + // DEATH: check if the person has died + if(personVec[id]->willDie() and + personVec[id]->getNumDaysTillDead() == personVec[id]->getNumDaysInfected()){ + #pragma omp atomic update + --num_currently_infected; + #pragma omp atomic update + ++total_num_deaths; + personVec[id]->die(can); + } + // RECOVERY: check if person has been infected for the duration of the disease + else if( !personVec[id]->willDie() and personVec[id]->getNumDaysInfected() >= sickDuration){ + #pragma omp atomic update + --num_currently_infected; + #pragma omp atomic update + ++total_num_recoveries; + personVec[id]->recover(can); + } + // STILL INFECTED: if not dead or recovered, increase number of days infected by 1 + else{ + personVec[id]->increaseNumDaysInfected(); + } + } + + // SUSCEPTIBLE + if(personVec[id]->getStatus() == susceptible){ + // Check if the person is within an infected radius + if(personVec[id]->checkIfInfectedNearby(personVec)){ + #pragma omp atomic update + ++total_num_infection_attempts; + // Determine if the person has been infected + if(personVec[id]->determineIfInfected(can, contagiousFactor, chance_distr(generator))){ + #pragma omp atomic update + --num_susceptible; + #pragma omp atomic update + ++num_currently_infected; + #pragma omp atomic update + ++total_num_infections; + personVec[id]->determineIsToDie(mortalityFactor, chance_distr(generator), sick_distr(generator)); + } + } + } + } + } // end main parallel block + //------------------------------------- Parallel Block End --------------------------------------- + + } // end simulation while loop + complete = true; + if(printInfo){ + // CALCULATIONS // + if(total_num_infection_attempts != 0){ // To avoid a divide-by-zero error (in case there were no infection attempts) + true_contagiousness = (total_num_infections/static_cast(total_num_infection_attempts)) * 100.0; + } + if(total_num_infections != 0){ // To avoid a divide-by-zero error (in case there were no infection attempts) + true_mortality = (total_num_deaths/static_cast(total_num_infections)) * 100.0; + } + for(unsigned i = 0; i < personVec.size(); ++i){ + avgInfectionLength += personVec[i]->getNumDaysInfected(); + } + avgInfectionLength /= total_num_infections; + + + // OUTPUT // + printf("\n***********************\ + \n* Statistics and data *\ + \n***********************\ + \n\ + \n*** Herd immunity achieved in %d days ***\ + \nSusceptible: %d\ + \nImmune: %d\ + \nDead: %d\ + \n", numDays, num_susceptible, + total_num_recoveries, total_num_deaths); + printf("\n*** Statistics ***\ + \nTotal number of infections: %d\ + \nTotal number of deaths: %d\ + \nTotal number of recoveries: %d\ + \nTrue contagiousness: %.2f%%\ + \nTrue mortality rate: %.2f%%\ + \n", total_num_infections, total_num_deaths, total_num_recoveries, + true_contagiousness, true_mortality); + + // Print thread attendance + if(takeAttendance){ + printf("\n*** Thread Attendance (-1 if absent) ***"); + for(unsigned i = 0; i < threadAttendance.size(); ++i){ + if(i%10 == 0){ + printf("\n"); + } + printf("%5d", threadAttendance[i]); + } + printf("\n"); + } + + printInfo = false; + } // end output + + } // end "complete" if + + can.sleep(); + + } // end Canvas while loop + + // DEALLOCATION OF OBJECT MEMORY // + for(int i = 0; i < numPersons; ++i){ + delete personVec[i]; + } + delete dayText; + personVec.clear(); + threadAttendance.clear(); + +} + +int main(int argc, char* argv[]){ + Canvas c(0, -1, 620, 620, "Pandemic Simulation", BLACK); + c.run(pandemicFunction, argc, argv); +} diff --git a/src/examples/Pandemic/testPerson.cpp b/src/examples/Pandemic/testPerson.cpp new file mode 100644 index 000000000..fd8a75b20 --- /dev/null +++ b/src/examples/Pandemic/testPerson.cpp @@ -0,0 +1,33 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [infectionRate] + 1 <= numPersons <= 100, defaults to 50 + 0 <= infectionRate <= 100, defaults to 20 + */ + +#include +#include +#include "Person.h" + +using namespace tsgl; + +void personFunction(Canvas& can) { + Person * p1 = new Person(0, 0, 50, susceptible); + + p1->draw(can); + + while (can.isOpen()) { + can.sleep(); + } + + // Deallocate all object memory + delete p1; + +} + +int main(int argc, char* argv[]){ + Canvas c(0, -1, 1820, 620, "Pandemic Simulation"); + c.setBackgroundColor(WHITE); + c.run(personFunction); +} diff --git a/src/tests/Pong/Ball.cpp b/src/examples/Pong/Ball.cpp similarity index 61% rename from src/tests/Pong/Ball.cpp rename to src/examples/Pong/Ball.cpp index 155fbbfdd..676f6f47c 100644 --- a/src/tests/Pong/Ball.cpp +++ b/src/examples/Pong/Ball.cpp @@ -13,16 +13,16 @@ * \return The constructed Ball object. */ Ball::Ball(Canvas& can, int & speed) { - mySpeed = speed; - myX = can.getWindowWidth() / 2-8; - myY = can.getWindowHeight() / 2-8; - do { - myDir = randfloat(1000) * 2 * PI; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while(myXX > -4 && myXX < 4); - myCircle = new Circle(myX, myY, 8, WHITE); - can.add(myCircle); + mySpeed = speed; + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while(myXX > -4 && myXX < 4); + myCircle = new Circle(myX, myY, 0, 8, 0,0,0, WHITE); + can.add(myCircle); } /*! @@ -30,7 +30,7 @@ Ball::Ball(Canvas& can, int & speed) { * \return myX The x-coordinate of the Ball object. */ float Ball::getX() const { - return myX; + return myX; } /*! @@ -38,7 +38,7 @@ float Ball::getX() const { * \return myY The y-coordinate of the Ball object. */ float Ball::getY() const { - return myY; + return myY; } /*! @@ -49,12 +49,12 @@ float Ball::getY() const { * \see Paddle class, Pong class. */ void Ball::invert(int choice) { - if(choice == 0) { - myYY = -myYY; - } else if(choice == 1) { - myXX = -myXX; - myYY += randfloat(1000) * 2 - 1; - } + if(choice == 0) { + myYY = -myYY; + } else if(choice == 1) { + myXX = -myXX; + myYY += randfloat(1000) * 2 - 1; + } } /*! @@ -62,17 +62,9 @@ void Ball::invert(int choice) { * \details Actually moves the Ball object around. */ void Ball::move() { - myX += myXX; - myY += myYY; - myCircle->setCenter(myX, myY); -} - - /*! - * \brief Private helper returning a random float. - * \details Calculates a random float to return. - */ -float Ball::randfloat(int divisor) { - return (rand() % divisor) / (float) divisor; + myX += myXX; + myY += myYY; + myCircle->setCenter(myX, myY, 0); } /*! @@ -82,11 +74,11 @@ float Ball::randfloat(int divisor) { * \param can Reference to the Canvas object that has the Ball object. */ void Ball::reset(Canvas& can) { - myX = can.getWindowWidth() / 2-8; - myY = can.getWindowHeight() / 2-8; - do { - myDir = randfloat(1000) * 2 * 3.14159f; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while (myXX > -4 && myXX < 4); + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while (myXX > -4 && myXX < 4); } diff --git a/src/tests/Pong/Ball.h b/src/examples/Pong/Ball.h similarity index 66% rename from src/tests/Pong/Ball.h rename to src/examples/Pong/Ball.h index e45a3b892..322f5c471 100644 --- a/src/tests/Pong/Ball.h +++ b/src/examples/Pong/Ball.h @@ -21,27 +21,26 @@ using namespace tsgl; */ class Ball { public: - Ball(Canvas& can, int & speed); + Ball(Canvas& can, int & speed); - float getX() const; + float getX() const; - float getY() const; + float getY() const; - void invert(int choice); + void invert(int choice); - void move(); + void move(); - void reset(Canvas& can); + void reset(Canvas& can); - /*! - * \brief Destroys the Ball object. - */ - virtual ~Ball() { delete myCircle; } + /*! + * \brief Destroys the Ball object. + */ + virtual ~Ball() { delete myCircle; } private: - float myX, myY, myXX, myYY, mySpeed, myDir; - float randfloat(int divisor = 10000); - Circle* myCircle; + float myX, myY, myXX, myYY, mySpeed, myDir; + Circle* myCircle; }; #endif /* BALL_H_ */ diff --git a/src/examples/Pong/Makefile b/src/examples/Pong/Makefile new file mode 100644 index 000000000..cc19ca124 --- /dev/null +++ b/src/examples/Pong/Makefile @@ -0,0 +1,87 @@ +# Makefile for Pong + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPong + +# Object files +ODIR = obj +_OBJ = Ball.o Paddle.o Pong.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Pong/Paddle.cpp b/src/examples/Pong/Paddle.cpp new file mode 100644 index 000000000..091c7d9c2 --- /dev/null +++ b/src/examples/Pong/Paddle.cpp @@ -0,0 +1,86 @@ +/* + * Paddle.cpp + */ + +#include "Paddle.h" + + /*! + * \brief Explicitly constructs a Paddle object. + * \details Explicit constructor for a Paddle object. + * \param can Reference to the Canvas to have the Paddle object on. + * \param speed Reference to the speed of the Paddle object. + * \return The constructed Paddle object. + */ +Paddle::Paddle(Canvas& can, int & speed, int side) { + mySpeed = speed; + myDir = myPoints = 0; + myY = - 32; + myRect = new Rectangle(0,myY,0,24,64,0,0,0, BLACK); + if(side == -1) { //Left side + myRect->setColor(BLUE); + myRect->setCenterX(-can.getWindowWidth() / 2 + 20); + } else if(side == 1) { //Right side + myRect->setColor(RED); + myRect->setCenterX(can.getWindowWidth() / 2 - 20); + } + can.add(myRect); +} + + /*! + * \brief Binds the buttons. + * \details Binds the buttons with the Canvas. In this case, the keys that move the paddle up and down. + * \param can Reference to the Canvas to bind the keys to. + * \param side The side that the Paddle object is on (left = -1 and the W and S keys are bound, right = 1 and the Up and Down arrow keys are bound). + */ +void Paddle::bindings(Canvas& can, int side) { + if(side == 1) { //Right + can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = 1;}); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = -1;}); + can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); + } else if(side == -1) { //Left + can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = 1;}); + can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = -1;}); + can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); + } +} + + /*! + * \brief Increments the Paddle object's score in the game of Pong. + */ +void Paddle::increment() { + ++myPoints; +} + + /*! + * \brief Actually Moves the Paddle object up or down. + */ +void Paddle::move() { + myY += mySpeed * myDir; + myRect->changeYBy(mySpeed * myDir); +} + + /*! + * \brief Accessor for the score of the Paddle object. + * \return myPoints The current score of the Paddle object in the game of Pong. + */ +int Paddle::getPoints() const { + return myPoints; +} + + /*! + * \brief Accessor for the current y-coordinate of the Paddle object. + * \return myY The y-coordinate of the Paddle object. + */ +float Paddle::getY() const { + return myY; +} + + /*! + * \brief Mutator for the direction of the Paddle object. + * \details Changes the current direction of the Paddle object (up or down). + */ +void Paddle::setDir(int direction) { + myDir = direction; +} diff --git a/src/tests/Pong/Paddle.h b/src/examples/Pong/Paddle.h similarity index 69% rename from src/tests/Pong/Paddle.h rename to src/examples/Pong/Paddle.h index b11db2b53..f5b56960b 100644 --- a/src/tests/Pong/Paddle.h +++ b/src/examples/Pong/Paddle.h @@ -25,33 +25,33 @@ using namespace tsgl; */ class Paddle { public: - Paddle(Canvas& can, int & speed, int side); + Paddle(Canvas& can, int & speed, int side); - void bindings(Canvas& can, int side); + void bindings(Canvas& can, int side); - void draw(Canvas& can, int side); + void draw(Canvas& can, int side); - void increment(); + void increment(); - void move(); + void move(); - int getPoints() const; + int getPoints() const; - float getY() const; + float getY() const; - void setDir(int direction); + void setDir(int direction); - /** - * \brief Destroys the Paddle object. - */ - ~Paddle() { delete myRect; } + /** + * \brief Destroys the Paddle object. + */ + ~Paddle() { delete myRect; } private: - int myDir; //-1 = up, 1 = down, 0 = stationary - int myPoints; //Score - int mySpeed; //Speed - float myY; //y-coordinate for Paddle - Rectangle * myRect; + int myDir; //-1 = up, 1 = down, 0 = stationary + int myPoints; //Score + int mySpeed; //Speed + float myY; //y-coordinate for Paddle + Rectangle * myRect; }; #endif /* PADDLE_H_ */ diff --git a/src/examples/Pong/Pong.cpp b/src/examples/Pong/Pong.cpp new file mode 100644 index 000000000..300de8672 --- /dev/null +++ b/src/examples/Pong/Pong.cpp @@ -0,0 +1,84 @@ +/* + * Pong.cpp + */ + +#include "Pong.h" + +using namespace tsgl; + + /*! + * \brief Explicitly construct the game, Pong. + * \details Explicit constructor for the game, Pong. It sets up the Paddle objects and the Ball object + * in order to play. + * \param can Reference to the Canvas to use when playing Pong. + * \param ballSpeed Reference to the ball speed to use in the game. + * \param paddleSpeed Reference to the paddle speed to use in the game. + */ +Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { + leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object + rightPaddle = new Paddle(can, paddleSpeed, 1); + //Bind the buttons + leftPaddle->bindings(can, -1); // W & S keys + rightPaddle->bindings(can, 1); // Up and Down arrow keys + pongBall = new Ball(can, ballSpeed); + leftScore = new Text(-64, can.getWindowHeight()/2 - 40, 0, L"0", "./assets/freefont/FreeSerif.ttf", 32, 0,0,0, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); + rightScore = new Text(64, can.getWindowHeight()/2 - 40, 0, L"0", "./assets/freefont/FreeSerif.ttf", 32, 0,0,0, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); + can.add(leftScore); can.add(rightScore); +} + + /*! + * \brief Draw the game of Pong. + * \details Actually draws all of the necessary components in order to play Pong. + * This also includes any necessary button bindings in order to move the Paddle objects. + * \param can Reference to the Canvas to draw on. + * \see Paddle class, Ball class. + */ +void Pong::draw(Canvas& can) { + // While the window has not been closed.... + while (can.isOpen()) { + can.sleep(); + // Move the ball + pongBall->move(); + // Handle ball boundary collisions + if (pongBall->getX() > can.getWindowWidth() / 2 + 8) { + leftPaddle->increment(); // Increment the points + leftScore->setText( std::to_wstring(leftPaddle->getPoints())); + pongBall->reset(can); // Reset the ball's position + } else if (pongBall->getX() < -can.getWindowWidth() / 2 -8) { + rightPaddle->increment(); + rightScore->setText( std::to_wstring(rightPaddle->getPoints())); + pongBall->reset(can); + } else if (pongBall->getY() > can.getWindowHeight() / 2 - 8 || pongBall->getY() < -can.getWindowHeight() / 2 + 8) pongBall->invert(0); //Invert the ball's y-coordinate changer + // Handle ball paddle collisions + // handle left + if (pongBall->getX() - 8 < -can.getWindowWidth() / 2 + 32 && + pongBall->getX() - 8 > -can.getWindowWidth() / 2 + 16 && + pongBall->getY() > leftPaddle->getY() - 32 && + pongBall->getY() < leftPaddle->getY() + 32) + { + pongBall->invert(1); + } + // handle right + else if (pongBall->getX() + 8 > can.getWindowWidth() / 2 - 32 && + pongBall->getX() + 8 < can.getWindowWidth() / 2 - 16 && + pongBall->getY() > rightPaddle->getY() - 32 && + pongBall->getY() < rightPaddle->getY() + 32) + { + pongBall->invert(1); + } + // Move the paddles if necessary + leftPaddle->move(); + rightPaddle->move(); + } +} + +/** + * \brief Destroys the Pong game object. + */ +Pong::~Pong() { + delete pongBall; + delete leftPaddle; + delete rightPaddle; + delete leftScore; + delete rightScore; +} \ No newline at end of file diff --git a/src/tests/Pong/Pong.h b/src/examples/Pong/Pong.h similarity index 82% rename from src/tests/Pong/Pong.h rename to src/examples/Pong/Pong.h index 38c7c423f..423117a18 100644 --- a/src/tests/Pong/Pong.h +++ b/src/examples/Pong/Pong.h @@ -29,16 +29,16 @@ using namespace tsgl; class Pong { public: - Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); + Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); - void draw(Canvas& can); + void draw(Canvas& can); - ~Pong(); + ~Pong(); private: - Paddle *leftPaddle, *rightPaddle; - Ball *pongBall; - Text *leftScore, *rightScore; + Paddle *leftPaddle, *rightPaddle; + Ball *pongBall; + Text *leftScore, *rightScore; }; #endif /* PONG_H_ */ diff --git a/src/tests/testPong.cpp b/src/examples/Pong/testPong.cpp similarity index 96% rename from src/tests/testPong.cpp rename to src/examples/Pong/testPong.cpp index 4e5535a7a..db2efd80d 100644 --- a/src/tests/testPong.cpp +++ b/src/examples/Pong/testPong.cpp @@ -4,7 +4,7 @@ * Usage: ./testPong */ -#include "Pong/Pong.h" +#include "Pong.h" using namespace tsgl; @@ -67,7 +67,6 @@ int main(int argc, char * argv[]) { ballSpeed = BALL_DEFAULT_SPEED; paddleSpeed = PADDLE_DEFAULT_SPEED; } - Canvas c(-1,-1,w,h,"Tennis for Two"); - c.setBackgroundColor(BLACK); + Canvas c(-1,-1,w,h,"Tennis for Two", BLACK); c.run(pongFunction,ballSpeed, paddleSpeed); } diff --git a/src/tests/ProducerConsumer/Consumer.cpp b/src/examples/ProducerConsumer/Consumer.cpp similarity index 67% rename from src/tests/ProducerConsumer/Consumer.cpp rename to src/examples/ProducerConsumer/Consumer.cpp index 548bce74c..8f9d1833a 100644 --- a/src/tests/ProducerConsumer/Consumer.cpp +++ b/src/examples/ProducerConsumer/Consumer.cpp @@ -14,12 +14,10 @@ Consumer::Consumer() : PCThread() { } * return: The constructed Consumer object. */ Consumer::Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { - myX = can.getWindowWidth() - 50; - myShape = new Rectangle(myX, myY, 40, 40, ColorInt(0, 0, 0), BLACK); - myShape->setCenter(myX, myY); - myShape->setLayer(1); - myCountLabel->setCenter(myX, myY); - myCountLabel->setLayer(2); + myX = can.getWindowWidth()/2 - 50; + myShape = new Square(myX, myY, 0, 40, 0,0,0, ColorInt(0, 0, 0)); + myShape->setCenter(myX, myY, 0); + myCountLabel->setCenter(myX, myY, 1); myCan->add(myShape); } @@ -28,16 +26,12 @@ Consumer::Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can) */ void Consumer::lock() { //Show waiting status - myShape->setColor( BLACK, WHITE ); + myShape->setColor( BLACK ); myCountLabel->setColor(WHITE); - if( myItem ) { - myCan->remove( myItem ); - delete myItem; - myItem = NULL; - } - + myCan->remove( myItem ); + delete myItem; buffer->consumerLock(); //Request lock - myShape->setColor( WHITE, BLACK ); + myShape->setColor( WHITE ); myCountLabel->setColor(BLACK); while( paused ) {} } @@ -50,15 +44,13 @@ void Consumer::act() { int endX = myShape->getCenterX()-50, endY = myShape->getCenterY(); animateItem(endX, endY); while( paused ) {} - ColorFloat* fillColor = myItem->getFillColor(); - myShape->setColor( fillColor, BLACK ); //Change Consumer color to Item color - myCountLabel->setColor(fillColor->getContrast()); - delete[] fillColor; + ColorFloat c = myItem->getColor(); + myShape->setColor( c ); //Change Consumer color to Item color + myCountLabel->setColor(c.getContrast()); count++; myCountLabel->setText( std::to_wstring(count) ); - if(count == 10) myCountLabel->setCenter(myX, myY); if(count == 100) { - myCountLabel->setFontSize(22); - myCountLabel->setCenter(myX, myY); + myCountLabel->setSize(22); + myCountLabel->setCenter(myX, myY, 1); } } @@ -68,14 +60,14 @@ void Consumer::act() { void Consumer::unlock() { // myCan->remove(myItem); // delete myItem; - // myItem = NULL; buffer->consumerUnlock(); while( paused ) {} } Consumer::~Consumer() { - if(myItem) { - delete myItem; - myItem = NULL; - } + // buffer->consumerUnlock(); + // if(myItem) { + // delete myItem; + // myItem = NULL; + // } } diff --git a/src/tests/ProducerConsumer/Consumer.h b/src/examples/ProducerConsumer/Consumer.h similarity index 100% rename from src/tests/ProducerConsumer/Consumer.h rename to src/examples/ProducerConsumer/Consumer.h diff --git a/src/examples/ProducerConsumer/Makefile b/src/examples/ProducerConsumer/Makefile new file mode 100644 index 000000000..2e072ff20 --- /dev/null +++ b/src/examples/ProducerConsumer/Makefile @@ -0,0 +1,87 @@ +# Makefile for ProducerConsumer + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = Queue.h \ + +# Main source file +TARGET = testProducerConsumer + +# Object files +ODIR = obj +_OBJ = Consumer.o PCThread.o Producer.o Thread.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/ProducerConsumer/PCThread.cpp b/src/examples/ProducerConsumer/PCThread.cpp similarity index 83% rename from src/tests/ProducerConsumer/PCThread.cpp rename to src/examples/ProducerConsumer/PCThread.cpp index da60b3ef0..70e5a1d75 100644 --- a/src/tests/ProducerConsumer/PCThread.cpp +++ b/src/examples/ProducerConsumer/PCThread.cpp @@ -28,19 +28,18 @@ PCThread::PCThread(Queue & sharedBuffer, unsigned long id, Canvas & can) count = 0; buffer = &sharedBuffer; //Get the handle to the Queue myCan = &can; //Get the handle to the Canvas - myY = 50 * (id + 1); + myY = can.getWindowHeight()/2 - 50 * (id + 1); myX = 0; //Set in subclass constructor myItem = NULL; myArrow = NULL; - myCountLabel = new Text( std::to_wstring(count), myX, myY+5, 24, WHITE); - myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); + myCountLabel = new Text( 0,0,1, std::to_wstring(count), "./assets/freefont/FreeSans.ttf", 24, 0,0,0, WHITE); // myCountLabel->setLayer(3); myCan->add( myCountLabel ); } //TODO: comment and improve void PCThread::wait() { - myCan->sleepFor( (rand()%10+3.0)/5.0 ); + myCan->sleepFor( (saferand(0, RAND_MAX)%10+3.0)/5.0 ); while( paused ) {} } @@ -58,31 +57,24 @@ void PCThread::animateItem(int endX, int endY) { const float timeInterval = 0.7; int startX = myItem->getCenterX(), startY = myItem->getCenterY(); - myArrow = new Arrow (startX, startY, endX, endY, BLACK, false); + myArrow = new Arrow (endX, endY, 1, startX, startY, 1, 5, 0,0,0, BLACK, false); myCan->add(myArrow); float deltaX = (endX - startX) / float(steps); //Change in x each step float deltaY = (endY - startY) / float(steps); //Change in y each step for(int i = 0; i <= steps; i++) { - myItem->setCenter( round( startX+ i*deltaX ), round(startY+i*deltaY)); + myItem->setCenter( round( startX+ i*deltaX ), round(startY+i*deltaY), 0); myCan->sleepFor( timeInterval / steps ); while( paused ) {} } myCan->remove(myArrow); delete myArrow; - myArrow = NULL; } PCThread::~PCThread() { delete myCountLabel; delete myShape; - if(myItem) { - delete myItem; - myItem = NULL; - } - if(myArrow) { - delete myArrow; - myArrow = NULL; - } + delete myItem; + delete myArrow; } diff --git a/src/tests/ProducerConsumer/PCThread.h b/src/examples/ProducerConsumer/PCThread.h similarity index 100% rename from src/tests/ProducerConsumer/PCThread.h rename to src/examples/ProducerConsumer/PCThread.h diff --git a/src/tests/ProducerConsumer/Producer.cpp b/src/examples/ProducerConsumer/Producer.cpp similarity index 70% rename from src/tests/ProducerConsumer/Producer.cpp rename to src/examples/ProducerConsumer/Producer.cpp index 2813e3213..2aa1d5e90 100644 --- a/src/tests/ProducerConsumer/Producer.cpp +++ b/src/examples/ProducerConsumer/Producer.cpp @@ -14,11 +14,9 @@ Producer::Producer() : PCThread() { } * @return: The constructed Producer object. */ Producer::Producer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { - myX = 50; //Set the x-coordinate to 50 - myShape = new Circle(myX, myY, 20, ColorInt(0, 0, 0), BLACK); - myShape->setLayer(1); - myCountLabel->setBottomLeftCorner(myX - 5, myY + 10); - myCountLabel->setLayer(2); + myX = -can.getWindowWidth()/2 + 50; //Set the x-coordinate to 50 + myShape = new Circle(myX, myY, 0, 20, 0,0,0, ColorInt(0, 0, 0)); + myCountLabel->setCenter(myX, myY, 1); myCan->add(myShape); } @@ -26,9 +24,9 @@ Producer::Producer(Queue & sharedBuffer, unsigned long id, Canvas & can) * randColor generates a new random ColorInt */ ColorInt Producer::randColor() { - int red = rand() % 255; - int green = rand() % 255; - int blue = rand() % 255; + int red = saferand(0,255); + int green = saferand(0,255); + int blue = saferand(0,255); return ColorInt(red, green, blue); } @@ -36,7 +34,7 @@ ColorInt Producer::randColor() { * nextItem generates a new Star with a random color */ Star* Producer::nextItem() { - return new Star(myX+50, myY, 20, 5, randColor() ); + return new Star(myX+50, myY, 0, 20, 5, 0,0,0, randColor() ); } /** @@ -44,10 +42,9 @@ Star* Producer::nextItem() { */ void Producer::wait() { myItem = nextItem(); - ColorFloat * fillColor = myItem->getFillColor(); - myShape->setColor( fillColor, BLACK ); - myCountLabel->setColor(fillColor->getContrast()); - delete[] fillColor; + ColorFloat c = myItem->getColor(); + myShape->setColor( c ); + myCountLabel->setColor(c.getContrast()); PCThread::wait(); } @@ -56,10 +53,10 @@ void Producer::wait() { */ void Producer::lock() { myCan->add( myItem ); - myShape->setColor( BLACK, WHITE ); + myShape->setColor( BLACK ); myCountLabel->setColor(WHITE); buffer->producerLock(); - myShape->setColor( WHITE, BLACK ); + myShape->setColor( WHITE ); myCountLabel->setColor(BLACK); while( paused ) {} } @@ -74,16 +71,14 @@ void Producer::act() { buffer->append(myItem, getId()); //Append something and pass your id along too //Show Item added to Queue float itAngle = (i*2*PI + PI)/8; // angle of item - int endX = 100*cos(itAngle)+300, endY = 100*sin(itAngle)+175; + int endX = 100*cos(itAngle), endY = 100 - 100*sin(itAngle); animateItem(endX, endY); count++; myCountLabel->setText( std::to_wstring(count) ); - if(count == 10) myCountLabel->setCenter(myX, myY); if(count == 100) { - myCountLabel->setFontSize(22); - myCountLabel->setCenter(myX, myY); + myCountLabel->setSize(22); + myCountLabel->setCenter(myX, myY, 1); } - myItem = NULL; } /** @@ -95,8 +90,8 @@ void Producer::unlock() { } Producer::~Producer() { - if(myItem) { - delete myItem; - myItem = NULL; - } + // if(myItem) { + // delete myItem; + // myItem = NULL; + // } } diff --git a/src/tests/ProducerConsumer/Producer.h b/src/examples/ProducerConsumer/Producer.h similarity index 100% rename from src/tests/ProducerConsumer/Producer.h rename to src/examples/ProducerConsumer/Producer.h diff --git a/src/tests/ProducerConsumer/Queue.h b/src/examples/ProducerConsumer/Queue.h similarity index 100% rename from src/tests/ProducerConsumer/Queue.h rename to src/examples/ProducerConsumer/Queue.h diff --git a/src/tests/ProducerConsumer/Thread.cpp b/src/examples/ProducerConsumer/Thread.cpp similarity index 100% rename from src/tests/ProducerConsumer/Thread.cpp rename to src/examples/ProducerConsumer/Thread.cpp diff --git a/src/tests/ProducerConsumer/Thread.h b/src/examples/ProducerConsumer/Thread.h similarity index 100% rename from src/tests/ProducerConsumer/Thread.h rename to src/examples/ProducerConsumer/Thread.h diff --git a/src/tests/testProducerConsumer.cpp b/src/examples/ProducerConsumer/testProducerConsumer.cpp similarity index 63% rename from src/tests/testProducerConsumer.cpp rename to src/examples/ProducerConsumer/testProducerConsumer.cpp index c6abe052b..4d67a39cf 100644 --- a/src/tests/testProducerConsumer.cpp +++ b/src/examples/ProducerConsumer/testProducerConsumer.cpp @@ -10,8 +10,8 @@ #include #include #include //for try-catch debugging -#include "ProducerConsumer/Producer.h" -#include "ProducerConsumer/Consumer.h" +#include "Producer.h" +#include "Consumer.h" using namespace tsgl; @@ -20,31 +20,29 @@ const int INNERRAD = 75; // radius of the inner circle const int OUTERRAD = 150; // radius of the outercircle const int CAPACITY = 8; const int WINDOW_WIDTH = 600, WINDOW_HEIGHT = 550, MAX_DATA = 8; //Size of Canvas and limit on amount of data to be stored in Queue -Canvas queueDisplay(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Producer-Consumer", FRAME ); //Canvas to draw on +Canvas queueDisplay(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Producer-Consumer", WHITE, nullptr, FRAME ); //Canvas to draw on Queue sharedBuffer(MAX_DATA, queueDisplay); //Shared buffer (has colored data) /** * displayLegend helps the main method by controlling the legendDisplay */ -void displayLegend(Circle *waitingCircle, Rectangle *waitingSquare, Canvas *queueDisplay) { +void displayLegend(Circle *waitingCircle, Square *waitingSquare, Canvas *queueDisplay) { Star** bufferArray = sharedBuffer.getArray(); int produceIndex; int cap = sharedBuffer.getCapacity(); int oldFirstIndex = 0; - ColorFloat* prodFillColor; - ColorFloat* consFillColor; + ColorFloat prodColor; + ColorFloat consColor; while( queueDisplay->isOpen() ) { if(!sharedBuffer.isEmpty()) { produceIndex = (sharedBuffer.getLastIndex() + cap - 1) % cap; - prodFillColor = bufferArray[produceIndex]->getFillColor(); - waitingCircle->setColor( prodFillColor[0], BLACK ); - delete[] prodFillColor; + prodColor = bufferArray[produceIndex]->getColor(); + waitingCircle->setColor( prodColor ); } if(oldFirstIndex != sharedBuffer.getFirstIndex()) { - consFillColor = bufferArray[oldFirstIndex]->getFillColor(); - waitingSquare->setColor( consFillColor[0], BLACK ); - delete[] consFillColor; + consColor = bufferArray[oldFirstIndex]->getColor(); + waitingSquare->setColor( consColor ); oldFirstIndex = sharedBuffer.getFirstIndex(); } } @@ -73,48 +71,49 @@ int main(int argc, char * argv[]) { srand(time(NULL)); // seed the random number generator + Background * queueBackground = queueDisplay.getBackground(); + float centerY = WINDOW_HEIGHT/2 - 175; //Fire up the visualization - queueDisplay.setBackgroundColor(WHITE); queueDisplay.start(); queueDisplay.bindToButton(TSGL_SPACE, TSGL_PRESS, []() { // toggle pause when spacebar is pressed PCThread::paused = !PCThread::paused; }); + queueBackground->drawRegularPolygon(0, centerY, 0, OUTERRAD, CAPACITY, 0,0,0, WHITE, true); + queueBackground->drawRegularPolygon(0, centerY, 0, INNERRAD, CAPACITY, 0,0,0, WHITE, true); + //Prepare the display with background items - int centerY = 175; - int centerX = 300; for(int i = 0; i < CAPACITY; i++) { float langle = (i*2*PI)/CAPACITY; // line angle - queueDisplay.drawLine(-INNERRAD*sin(langle)+centerX, INNERRAD*cos(langle)+centerY, -OUTERRAD*sin(langle)+centerX, OUTERRAD*cos(langle)+centerY, BLACK); + queueBackground->drawLine(-INNERRAD*sin(langle), INNERRAD*cos(langle) + centerY,0, -OUTERRAD*sin(langle), OUTERRAD*cos(langle)+centerY,0, 0,0,0, BLACK); } - queueDisplay.drawRegularPolygon(centerX, centerY, OUTERRAD, CAPACITY, BLACK, false); - queueDisplay.drawRegularPolygon(centerX, centerY, INNERRAD, CAPACITY, BLACK, false); + const std::string FONT = "./assets/freefont/FreeSerif.ttf"; //Add notes to bottom of main Canvas - queueDisplay.drawText("*Numbers indicate counts of items produced and consumed", WINDOW_WIDTH-370, WINDOW_HEIGHT-20, 12, BLACK); + queueBackground->drawText(0,-WINDOW_HEIGHT/2+20, 0, L"*Numbers indicate counts of items produced and consumed", FONT, 20, 0,0,0, BLACK); // Label Readers and Writers - queueDisplay.drawText("Producers", 30, 20, 24, BLACK); - queueDisplay.drawText("Consumers", WINDOW_WIDTH-150, 20, 24, BLACK); + queueBackground->drawText(-WINDOW_WIDTH/2 + 60, WINDOW_HEIGHT/2-10,0, L"Producers", FONT, 24, 0,0,0, BLACK); + queueBackground->drawText(WINDOW_WIDTH/2 - 60, WINDOW_HEIGHT/2-10,0, L"Consumers", FONT, 24, 0,0,0, BLACK); - int LEGENDOFFSET = 300; + int LEGENDOFFSET = -25; //Text labels - queueDisplay.drawText("producing",100,70+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("waiting for lock",100,130+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("holding lock",100,190+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("consuming",350,70+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("waiting for lock",350,130+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("holding lock",350,190+LEGENDOFFSET,24,BLACK); + queueBackground->drawText(-140,LEGENDOFFSET-60,0,L"producing",FONT,24, 0,0,0, BLACK); + queueBackground->drawText(-140,LEGENDOFFSET-120,0,L"waiting for lock",FONT,24, 0,0,0, BLACK); + queueBackground->drawText(-140,LEGENDOFFSET-180,0,L"holding lock",FONT,24, 0,0,0, BLACK); + queueBackground->drawText(140,LEGENDOFFSET-60,0,L"consuming",FONT,24, 0,0,0, BLACK); + queueBackground->drawText(140,LEGENDOFFSET-120,0,L"waiting for lock",FONT,24, 0,0,0, BLACK); + queueBackground->drawText(140,LEGENDOFFSET-180,0,L"holding lock",FONT,24, 0,0,0, BLACK); //Create legend items - Circle waitingCircle(50, 60+LEGENDOFFSET, 20, BLACK, BLACK); //waiting for lock - Circle thinkingCircle(50, 120+LEGENDOFFSET, 20, BLACK, true); //waiting, not seeking lock - Circle lockCircle(50, 180+LEGENDOFFSET, 20, BLACK, false); //has lock - Rectangle waitingSquare(WINDOW_WIDTH-70, 40+LEGENDOFFSET, 40, 40, BLACK, BLACK); - Rectangle thinkingSquare(WINDOW_WIDTH-70, 100+LEGENDOFFSET, 40, 40, BLACK, true); - Rectangle lockSquare(WINDOW_WIDTH-70, 160+LEGENDOFFSET, 40, 40, BLACK, false); + Circle waitingCircle(-WINDOW_WIDTH/2 + 50, LEGENDOFFSET-60, 0, 20, 0,0,0, BLACK); //waiting for lock + Circle thinkingCircle(-WINDOW_WIDTH/2 + 50, LEGENDOFFSET-120, 0, 20, 0,0,0, BLACK); //waiting, not seeking lock + Circle lockCircle(-WINDOW_WIDTH/2 + 50, LEGENDOFFSET-180, 0, 20, 0,0,0, BLACK); //has lock + Square waitingSquare(WINDOW_WIDTH/2-50, LEGENDOFFSET-60, 0, 40, 0,0,0, BLACK); + Square thinkingSquare(WINDOW_WIDTH/2-50, LEGENDOFFSET-120, 0, 40, 0,0,0, BLACK); + Square lockSquare(WINDOW_WIDTH/2-50, LEGENDOFFSET-180, 0, 40, 0,0,0, BLACK); queueDisplay.add( &waitingCircle ); queueDisplay.add( &thinkingCircle ); queueDisplay.add( &lockCircle ); queueDisplay.add( &waitingSquare ); queueDisplay.add( &thinkingSquare ); queueDisplay.add( &lockSquare ); @@ -147,22 +146,24 @@ int main(int argc, char * argv[]) { queueDisplay.wait(); + while( !sharedBuffer.isEmpty() ) { + Star * tempPtr = sharedBuffer.remove(); + delete tempPtr; + } + //Now join them for(int p = 0; p < numProducers; p++) { //Join the pthreads for the Producers pro[p]->join(); + delete pro[p]; } for(int c = 0; c < numConsumers; c++) { //Join the pthreads for the Consumers con[c]->join(); + delete con[c]; } legendUpdater.join(); - while( !sharedBuffer.isEmpty() ) { - Star * tempPtr = sharedBuffer.remove(); - delete tempPtr; - } - delete [] pro; delete [] con; pro = NULL; diff --git a/src/tests/ReaderWriter/FLock.cpp b/src/examples/ReaderWriter/FLock.cpp similarity index 100% rename from src/tests/ReaderWriter/FLock.cpp rename to src/examples/ReaderWriter/FLock.cpp diff --git a/src/tests/ReaderWriter/FLock.h b/src/examples/ReaderWriter/FLock.h similarity index 100% rename from src/tests/ReaderWriter/FLock.h rename to src/examples/ReaderWriter/FLock.h diff --git a/src/tests/ReaderWriter/Lock.cpp b/src/examples/ReaderWriter/Lock.cpp similarity index 100% rename from src/tests/ReaderWriter/Lock.cpp rename to src/examples/ReaderWriter/Lock.cpp diff --git a/src/tests/ReaderWriter/Lock.h b/src/examples/ReaderWriter/Lock.h similarity index 98% rename from src/tests/ReaderWriter/Lock.h rename to src/examples/ReaderWriter/Lock.h index 5f9ccb4f8..2e878ad8f 100644 --- a/src/tests/ReaderWriter/Lock.h +++ b/src/examples/ReaderWriter/Lock.h @@ -24,6 +24,7 @@ class Lock { public: Lock(); //Default constructor Lock(RWDatabase* data); //Explicit constructor + virtual ~Lock() {} virtual void readLock() = 0; //Must be defined by subclass virtual void readUnlock() = 0; //Must be defined by subclass virtual void writeLock() = 0; //Must be defined by subclass diff --git a/src/examples/ReaderWriter/Makefile b/src/examples/ReaderWriter/Makefile new file mode 100644 index 000000000..a72e6f3e2 --- /dev/null +++ b/src/examples/ReaderWriter/Makefile @@ -0,0 +1,87 @@ +# Makefile for ReaderWriter + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = RWDatabase.h \ + +# Main source file +TARGET = testReaderWriter + +# Object files +ODIR = obj +_OBJ = FLock.o Lock.o Reader.o RLock.o RWThread.o Thread.o WLock.o Writer.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/ReaderWriter/RLock.cpp b/src/examples/ReaderWriter/RLock.cpp similarity index 100% rename from src/tests/ReaderWriter/RLock.cpp rename to src/examples/ReaderWriter/RLock.cpp diff --git a/src/tests/ReaderWriter/RLock.h b/src/examples/ReaderWriter/RLock.h similarity index 100% rename from src/tests/ReaderWriter/RLock.h rename to src/examples/ReaderWriter/RLock.h diff --git a/src/tests/ReaderWriter/RWDatabase.h b/src/examples/ReaderWriter/RWDatabase.h similarity index 94% rename from src/tests/ReaderWriter/RWDatabase.h rename to src/examples/ReaderWriter/RWDatabase.h index ffdd1cf1d..31e209f9a 100644 --- a/src/tests/ReaderWriter/RWDatabase.h +++ b/src/examples/ReaderWriter/RWDatabase.h @@ -27,6 +27,7 @@ class RWDatabase { int getMaxCapacity() { return maxCapacity; }//Get maximum items in vector Item read(unsigned index); //Access item at index void write(Item it, unsigned index); //Set item at index + ~RWDatabase(); protected: std::vector vec; @@ -82,4 +83,11 @@ void RWDatabase::write(Item it, unsigned index) { } } +template +RWDatabase::~RWDatabase() { + for (int i = 0; i < vec.size(); i++) { + delete vec[i]; + } +} + #endif /*RWDATA_H_*/ diff --git a/src/tests/ReaderWriter/RWThread.cpp b/src/examples/ReaderWriter/RWThread.cpp similarity index 78% rename from src/tests/ReaderWriter/RWThread.cpp rename to src/examples/ReaderWriter/RWThread.cpp index e210790ef..2382ebd6a 100644 --- a/src/tests/ReaderWriter/RWThread.cpp +++ b/src/examples/ReaderWriter/RWThread.cpp @@ -5,7 +5,7 @@ int RWThread::WAIT_RANGE = 40, RWThread::WAIT_MIN = 15; // 40 and 15 worked very well with the new version of ReaderWriter // Still need to have these change based on number of threads. const int RWThread::width = 20; //Width of each object - const int RWThread::dataX = 200, RWThread::dataY = 670; //Bottom left coordinates of the data area + const int RWThread::dataX = -100, RWThread::dataY = -270; //Bottom left coordinates of the data area const int RWThread::dataHeight = 600, RWThread::dataWidth = 200; //Dimensions of the data area int RWThread::threadCount = 0; float RWThread::access_wait = 1.0; @@ -40,17 +40,19 @@ RWThread::RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned data = &sharedDatabase; //Get the handle to the Database monitor = &lock; //Get the handle to the monitor myCan = &can; //Get the handle to the Canvas - myY = RWThread::dataY - 50 * (id + 1); + myY = RWThread::dataY + 50 * (id + 1); myX = 0; //Set in subclass constructor - myCircle = new Circle(myX, myY, 20, GRAY); //Move based on new x in subclass - myCircle->setLayer(3); + myCircle = new Circle(myX, myY, 0, 20, 0,0,0, GRAY); //Move based on new x in subclass myCan->add(myCircle); - myCountLabel = new Text( to_wstring(count), myX, myY+5, 24, BLACK); - myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); - myCountLabel->setLayer(4); + myCountLabel = new Text( myX, myY+5, 1, to_wstring(count), "./assets/freefont/FreeSans.ttf", 24, 0,0,0, BLACK); myCan->add( myCountLabel ); } +RWThread::~RWThread() { + delete myCountLabel; + delete myCircle; +} + void RWThread::run() { while( myCan->isOpen() ) { lock(); @@ -61,5 +63,5 @@ void RWThread::run() { } void RWThread::wait() { - myCan->sleepFor( (rand()%RWThread::WAIT_RANGE+RWThread::WAIT_MIN)/10.0 ); //Wait for a random time + myCan->sleepFor( (saferand(0,RWThread::WAIT_RANGE)+RWThread::WAIT_MIN)/10.0 ); //Wait for a random time } diff --git a/src/tests/ReaderWriter/RWThread.h b/src/examples/ReaderWriter/RWThread.h similarity index 98% rename from src/tests/ReaderWriter/RWThread.h rename to src/examples/ReaderWriter/RWThread.h index aba8058ff..48b73b7f9 100644 --- a/src/tests/ReaderWriter/RWThread.h +++ b/src/examples/ReaderWriter/RWThread.h @@ -21,6 +21,7 @@ class RWThread : public Thread { public: RWThread(); //Default constructor RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor + virtual ~RWThread(); void run(); void wait(); virtual void lock() = 0; //Must be implemented by subclass diff --git a/src/tests/ReaderWriter/Reader.cpp b/src/examples/ReaderWriter/Reader.cpp similarity index 66% rename from src/tests/ReaderWriter/Reader.cpp rename to src/examples/ReaderWriter/Reader.cpp index 8757d9584..87235cfa5 100644 --- a/src/tests/ReaderWriter/Reader.cpp +++ b/src/examples/ReaderWriter/Reader.cpp @@ -14,9 +14,9 @@ Reader::Reader() : RWThread() { } * \return: The constructed Reader object. */ Reader::Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { - myX = can.getWindowWidth()-50; - myCircle->setCenter(myX, myY); - myCountLabel->setCenter(myX, myY); + myX = can.getWindowWidth()/2-50; + myCircle->setCenter(myX, myY, 0); + myCountLabel->setCenter(myX, myY, 1); } /** @@ -25,8 +25,7 @@ Reader::Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned lon * \details Includes a half second pause */ void Reader::drawArrow(int x, int y) { - Arrow arrow(myCircle->getCenterX()-20, myY, x, y, BLACK, false); - arrow.setLayer(5); + Arrow arrow(x, y, 2, myCircle->getCenterX()-20, myY, 2, 8, 0,0,0, BLACK, false); myCan->add(&arrow); myCan->sleepFor(0.5); while( paused ) {} @@ -35,23 +34,22 @@ void Reader::drawArrow(int x, int y) { //TODO: comment void Reader::lock() { - myCircle->setCenter(myX-75, myY); //Move towards data - myCountLabel->setCenter(myX-75, myY); + myCircle->setCenter(myX-75, myY, 0); //Move towards data + myCountLabel->setCenter(myX-75, myY, 1); monitor->readLock(); //Lock data for reading myCan->sleepFor(RWThread::access_wait); while( paused ) {} - myCircle->setCenter(myX-127, myY); //Move inside data - myCountLabel->setCenter(myX-127, myY); + myCircle->setCenter(myX-127, myY, 0); //Move inside data + myCountLabel->setCenter(myX-127, myY, 1); } //TODO: comment void Reader::act() { //Read - Rectangle * rec = data->read(rand()%data->getItemCount()); //Get the color - ColorFloat* fillColor = rec->getFillColor(); - myCircle->setColor( fillColor[0] ); - myCountLabel->setColor( fillColor[0].getContrast() ); - delete[] fillColor; + Rectangle * rec = data->read(saferand(0, data->getItemCount()-1)); //Get the color + ColorFloat c = rec->getColor(); + myCircle->setColor( c ); + myCountLabel->setColor( c.getContrast() ); //Draw and erase the arrow drawArrow(rec->getCenterX(), rec->getCenterY()); @@ -62,10 +60,10 @@ void Reader::unlock() { //Release lock count++; myCountLabel->setText( to_wstring(count) ); //Finished another read if( count == 100 ) { - myCountLabel->setFontSize(22); + myCountLabel->setSize(22); } while( paused ) {} - myCircle->setCenter(myX, myY); //Return to home location - myCountLabel->setCenter(myX, myY); + myCircle->setCenter(myX, myY, 0); //Return to home location + myCountLabel->setCenter(myX, myY, 1); monitor->readUnlock(); //Unlock the data } diff --git a/src/tests/ReaderWriter/Reader.h b/src/examples/ReaderWriter/Reader.h similarity index 100% rename from src/tests/ReaderWriter/Reader.h rename to src/examples/ReaderWriter/Reader.h diff --git a/src/tests/ReaderWriter/Thread.cpp b/src/examples/ReaderWriter/Thread.cpp similarity index 100% rename from src/tests/ReaderWriter/Thread.cpp rename to src/examples/ReaderWriter/Thread.cpp diff --git a/src/tests/ReaderWriter/Thread.h b/src/examples/ReaderWriter/Thread.h similarity index 100% rename from src/tests/ReaderWriter/Thread.h rename to src/examples/ReaderWriter/Thread.h diff --git a/src/tests/ReaderWriter/WLock.cpp b/src/examples/ReaderWriter/WLock.cpp similarity index 100% rename from src/tests/ReaderWriter/WLock.cpp rename to src/examples/ReaderWriter/WLock.cpp diff --git a/src/tests/ReaderWriter/WLock.h b/src/examples/ReaderWriter/WLock.h similarity index 100% rename from src/tests/ReaderWriter/WLock.h rename to src/examples/ReaderWriter/WLock.h diff --git a/src/tests/ReaderWriter/Writer.cpp b/src/examples/ReaderWriter/Writer.cpp similarity index 64% rename from src/tests/ReaderWriter/Writer.cpp rename to src/examples/ReaderWriter/Writer.cpp index 9c7447725..3f4f72798 100644 --- a/src/tests/ReaderWriter/Writer.cpp +++ b/src/examples/ReaderWriter/Writer.cpp @@ -15,14 +15,12 @@ Writer::Writer() : RWThread() { dataLabel = NULL; } * \return: The constructed Writer object. */ Writer::Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { - myX = 50; //Set the x-coordinate to 50 - myCircle->setCenter(myX, myY); - myCountLabel->setCenter(myX, myY); + myX = -can.getWindowWidth()/2 + 50; //Set the x-coordinate to 50 + myCircle->setCenter(myX, myY, 0); + myCountLabel->setCenter(myX, myY, 1); if( !dataLabel ) { - dataLabel = new Text(L"0/300", RWThread::dataX-40, RWThread::dataY-RWThread::dataHeight-20, 16, BLACK); - dataLabel->setCenter(RWThread::dataX - 20, RWThread::dataY-RWThread::dataHeight-15); + dataLabel = new Text(RWThread::dataX - 20, RWThread::dataY+RWThread::dataHeight+15, 1, L"0/300", "./assets/freefont/FreeSans.ttf", 16, 0,0,0, BLACK); myCan->add( dataLabel ); - dataLabel->setLayer(3); } } @@ -32,8 +30,7 @@ Writer::Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned lon * \details Includes a half second pause */ void Writer::drawArrow(int x, int y) { - Arrow arrow(myCircle->getCenterX()+20, myY, x, y, BLACK); - arrow.setLayer(5); + Arrow arrow(x, y, 2, myCircle->getCenterX()+20, myY, 2, 8, 0,0,0, BLACK); myCan->add(&arrow); myCan->sleepFor(0.5); while( paused ) {} @@ -44,9 +41,9 @@ void Writer::drawArrow(int x, int y) { * \brief newColor() generates a new random color for writing. */ ColorInt Writer::randColor() { - int red = rand() % 255; - int green = rand() % 255; - int blue = rand() % 255; + int red = saferand(0,255); + int green = saferand(0,255); + int blue = saferand(0,255); return ColorInt(red, green, blue); } @@ -54,7 +51,7 @@ ColorInt Writer::randColor() { * \brief randIndex() generates an index number to add a new item */ int Writer::randIndex() { - int i = rand()%(data->getMaxCapacity()); //Random index between 0 and the max number of items in data + int i = saferand(0,data->getMaxCapacity()); //Random index between 0 and the max number of items in data if( i > data->getItemCount() ) //Max index is next empty index i = data->getItemCount(); return i; @@ -64,16 +61,16 @@ int Writer::randIndex() { * \brief makeRec() creates a new Rectangle representing a random color */ Rectangle * Writer::makeRec(int index) { - int x = dataX + index%(200/RWThread::width) * RWThread::width; // start of data + column - int y = dataY - (index/(200/RWThread::width) + 1) * RWThread::width; // start of data + row + int x = dataX + index%(200/RWThread::width) * RWThread::width + RWThread::width/2; // start of data + column + int y = dataY + (index/(200/RWThread::width) + 1) * RWThread::width - RWThread::width/2; // start of data + row - return new Rectangle(x, y, RWThread::width, RWThread::width, randColor()); + return new Rectangle(x, y, 0, RWThread::width, RWThread::width, 0,0,0, randColor()); } //TODO: comment void Writer::lock() { - myCircle->setCenter(myX+75, myY); //Move in toward data - myCountLabel->setCenter(myX+75, myY); + myCircle->setCenter(myX+75, myY, 0); //Move in toward data + myCountLabel->setCenter(myX+75, myY, 1); monitor->writeLock(); //Lock data for writing myCan->sleepFor(RWThread::access_wait); } @@ -82,8 +79,8 @@ void Writer::lock() { void Writer::act() { while( paused ) {} int id = randIndex(); - myCircle->setCenter(myX+127, myY); //Move inside data - myCountLabel->setCenter(myX+127, myY); + myCircle->setCenter(myX+127, myY, 0); //Move inside data + myCountLabel->setCenter(myX+127, myY, 1); Rectangle * rec; if( id < data->getItemCount() ) { //Change the color of an item rec = data->read(id); @@ -91,14 +88,12 @@ void Writer::act() { } else { //Create a new item rec = makeRec(id); //Make random color at random index data->write(rec, id); // Write the item to the data - rec->setLayer(3); myCan->add(rec); dataLabel->setText( to_wstring( data->getItemCount() ) + L"/" + to_wstring( data->getMaxCapacity() ) ); } - ColorFloat* fillColor = rec->getFillColor(); - myCircle->setColor( fillColor[0] ); - myCountLabel->setColor(fillColor[0].getContrast()); - delete[] fillColor; + ColorFloat c = rec->getColor(); + myCircle->setColor( c ); + myCountLabel->setColor(c.getContrast()); //Draw an arrow down to the item drawArrow(rec->getCenterX(), rec->getCenterY()); @@ -109,10 +104,10 @@ void Writer::unlock() { //Release lock count++; myCountLabel->setText( to_wstring(count) ); //Finished another write if( count == 100 ) { - myCountLabel->setFontSize(22); + myCountLabel->setSize(22); } while( paused ) {} - myCircle->setCenter(myX, myY); //Return to home location - myCountLabel->setCenter(myX, myY); + myCircle->setCenter(myX, myY, 0); //Return to home location + myCountLabel->setCenter(myX, myY, 1); monitor->writeUnlock(); //Unlock the data for writing } diff --git a/src/tests/ReaderWriter/Writer.h b/src/examples/ReaderWriter/Writer.h similarity index 97% rename from src/tests/ReaderWriter/Writer.h rename to src/examples/ReaderWriter/Writer.h index 33c5871a4..987466e78 100644 --- a/src/tests/ReaderWriter/Writer.h +++ b/src/examples/ReaderWriter/Writer.h @@ -29,7 +29,6 @@ class Writer : public RWThread { private: ColorInt randColor(); int randIndex(); - TextureHandler loader; void drawArrow(int x, int y); Rectangle * makeRec(int index); static Text * dataLabel; diff --git a/src/tests/testReaderWriter.cpp b/src/examples/ReaderWriter/testReaderWriter.cpp similarity index 65% rename from src/tests/testReaderWriter.cpp rename to src/examples/ReaderWriter/testReaderWriter.cpp index 86019887c..50181fe7a 100644 --- a/src/tests/testReaderWriter.cpp +++ b/src/examples/ReaderWriter/testReaderWriter.cpp @@ -9,13 +9,13 @@ //#include #include #include -#include "ReaderWriter/Reader.h" -#include "ReaderWriter/Writer.h" -#include "ReaderWriter/RWDatabase.h" -#include "ReaderWriter/Lock.h" -#include "ReaderWriter/RLock.h" -#include "ReaderWriter/WLock.h" -#include "ReaderWriter/FLock.h" +#include "Reader.h" +#include "Writer.h" +#include "RWDatabase.h" +#include "Lock.h" +#include "RLock.h" +#include "WLock.h" +#include "FLock.h" using namespace tsgl; //Constants @@ -34,11 +34,10 @@ int main(int argc, char* argv[]) { int numWriters = ( (argc > 2) && (atoi(argv[2]) > 0) && (atoi(argv[2]) <= 9) ) ? atoi(argv[2]) : 6; //Start Reader-Writer visualization - Canvas can(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Reader-Writer", 1.0f/2); //Canvas to draw on + Canvas can(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Reader-Writer", WHITE, nullptr, 1.0f/2); //Canvas to draw on //Start the visualization can.start(); - can.setBackgroundColor(WHITE); //Create monitor Lock * lock; @@ -61,23 +60,26 @@ int main(int argc, char* argv[]) { Reader ** readers = new Reader*[numReaders]; //Array of Readers Writer ** writers = new Writer*[numWriters]; //Array of Writers + std::string FONT = "./assets/freefont/FreeSerif.ttf"; + + Background * bg = can.getBackground(); //Create labels - can.drawRectangle(RWThread::dataX-MARGIN, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth+2*MARGIN, RWThread::dataHeight, GRAY); - can.drawRectangle(RWThread::dataX, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth, RWThread::dataHeight, DARKGRAY); // draw data area - can.drawLine(RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY, BLACK); - can.drawLine(RWThread::dataX-MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX-MARGIN*2.5, RWThread::dataY, BLACK); - can.drawText(lockString, 100, RWThread::dataY + 40, 20, BLACK); - can.drawText(L"Numbers indicate", WINDOW_WIDTH-200, RWThread::dataY + 40, 20, BLACK); - can.drawText(L"counts of reads/writes", WINDOW_WIDTH-200, RWThread::dataY + 60, 20, BLACK); - can.drawText(L"Writers", 72, 60, 24, BLACK); - can.drawText(L"Readers", WINDOW_WIDTH-140, 60, 24, BLACK); - can.drawText(L"Shared Data Store", 226, 692, 20, BLACK); - - //Create and rotate more labels - can.drawText(L"Thinking", 484, 127, 28, GRAY, "", PI/2); - can.drawText(L"Waiting", 423, 127, 28, GRAY, "", PI/2); - can.drawText(L"Thinking", 14, 127, 28, GRAY, "", -PI/2); - can.drawText(L"Waiting", 88, 127, 28, GRAY, "", -PI/2); + bg->drawRectangle(0, RWThread::dataY + RWThread::dataHeight/2, 0, RWThread::dataWidth+2*MARGIN, RWThread::dataHeight, 0,0,0, GRAY); + bg->drawRectangle(0, RWThread::dataY + RWThread::dataHeight/2, 0, RWThread::dataWidth, RWThread::dataHeight, 0,0,0, DARKGRAY); // draw data area + bg->drawLine(RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY+RWThread::dataHeight, 0, RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY, 0, 0,0,0, BLACK); + bg->drawLine(RWThread::dataX-MARGIN*2.5, RWThread::dataY+RWThread::dataHeight, 0, RWThread::dataX-MARGIN*2.5, RWThread::dataY, 0, 0,0,0, BLACK); + bg->drawText(-RWThread::dataWidth/2-MARGIN*2.5, RWThread::dataY - 20, 0, lockString, FONT, 20, 0,0,0, BLACK); + bg->drawText(RWThread::dataWidth/2+MARGIN*2.4, RWThread::dataY - 20, 0, L"Numbers indicate", FONT, 20, 0,0,0, BLACK); + bg->drawText(RWThread::dataWidth/2+MARGIN*2.4, RWThread::dataY - 40, 0, L"counts of reads/writes", FONT, 20, 0,0,0, BLACK); + bg->drawText(-RWThread::dataWidth/2-MARGIN*2.5, WINDOW_HEIGHT/2-55, 0, L"Writers", FONT, 24, 0,0,0, BLACK); + bg->drawText( RWThread::dataWidth/2+MARGIN*2.5, WINDOW_HEIGHT/2-55, 0, L"Readers", FONT, 24, 0,0,0, BLACK); + bg->drawText(0, -285, 0, L"Shared Data Store", FONT, 20, 0,0,0, BLACK); + + // //Create and rotate more labels + bg->drawText(RWThread::dataX-MARGIN*1.75, 275, 0, L"Thinking", FONT, 28, 90,0,0, GRAY); + bg->drawText(RWThread::dataX-MARGIN*3.25, 275, 0, L"Waiting", FONT, 28, 90,0,0, GRAY); + bg->drawText(RWThread::dataWidth/2+MARGIN*1.75, 275, 0, L"Thinking", FONT, 28, -90,0,0, GRAY); + bg->drawText(RWThread::dataWidth/2+MARGIN*3.25, 275, 0, L"Waiting", FONT, 28, -90,0,0, GRAY); //Fill the Reader and Writer arrays with their objects for(int i = 0; i < numReaders; i++) { @@ -122,14 +124,18 @@ int main(int argc, char* argv[]) { //End threads for(int i = 0; i < numReaders; i++) { readers[i]->join(); + delete readers[i]; } for(int i = 0; i < numWriters; i++) { writers[i]->join(); + delete writers[i]; } //Cleanup delete [] readers; delete [] writers; + delete database; + delete lock; readers = NULL; writers = NULL; diff --git a/src/examples/SeaUrchin/Makefile b/src/examples/SeaUrchin/Makefile new file mode 100644 index 000000000..d030a646d --- /dev/null +++ b/src/examples/SeaUrchin/Makefile @@ -0,0 +1,87 @@ +# Makefile for SeaUrchin + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSeaUrchin + +# Object files +ODIR = obj +_OBJ = SeaUrchin.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/SeaUrchin/SeaUrchin.cpp b/src/examples/SeaUrchin/SeaUrchin.cpp new file mode 100644 index 000000000..042b62f65 --- /dev/null +++ b/src/examples/SeaUrchin/SeaUrchin.cpp @@ -0,0 +1,33 @@ +/* + * SeaUrchin.cpp + */ + +#include "SeaUrchin.h" + +SeaUrchin::SeaUrchin(Canvas& can, int threadId) { + myX = -can.getWindowWidth() / 2 + 60; + myY = -can.getWindowHeight() / 2 + 60; + myX += (threadId % 8) * 110; + myY += (threadId / 8) * 110; + float delta = 180 / MY_SPOKES; + myColor = Colors::highContrastColor(threadId); + for(int i = 0; i < MY_SPOKES; i++) { + Line * l = new Line(myX, myY, 0, 100, i * delta, 0, 0, myColor); + lines.push_back(l); + can.add(l); + } +} + +void SeaUrchin::move(Canvas& can) { + float delta = 180 / MY_SPOKES; + for(int j = 0; j < MY_SPOKES; ++j) { + lines[j]->setYaw(j * delta + can.getReps() * 180 / PI); + } +} + +SeaUrchin::~SeaUrchin() { + for (unsigned int i = 0; i < lines.size(); i++) { + delete lines[i]; + } +} + diff --git a/src/tests/SeaUrchin/SeaUrchin.h b/src/examples/SeaUrchin/SeaUrchin.h similarity index 97% rename from src/tests/SeaUrchin/SeaUrchin.h rename to src/examples/SeaUrchin/SeaUrchin.h index 4c2893450..e163e22d3 100644 --- a/src/tests/SeaUrchin/SeaUrchin.h +++ b/src/examples/SeaUrchin/SeaUrchin.h @@ -48,7 +48,7 @@ class SeaUrchin { private: static const int MY_SPOKES = 8; - int myOldX, myOldY, myNewX, myNewY; + int myX, myY; ColorFloat myColor; std::vector lines; }; diff --git a/src/tests/testSeaUrchin.cpp b/src/examples/SeaUrchin/testSeaUrchin.cpp similarity index 95% rename from src/tests/testSeaUrchin.cpp rename to src/examples/SeaUrchin/testSeaUrchin.cpp index ba703305e..17813268d 100644 --- a/src/tests/testSeaUrchin.cpp +++ b/src/examples/SeaUrchin/testSeaUrchin.cpp @@ -7,7 +7,7 @@ #include "tsgl.h" #include -#include "SeaUrchin/SeaUrchin.h" +#include "SeaUrchin.h" using namespace tsgl; @@ -58,8 +58,7 @@ void seaUrchinFunction(Canvas& can, int threads) { int main(int argc, char * argv[]) { int nthreads = (argc > 1) ? atoi(argv[1]) : 16; //Number of threads clamp(nthreads,1,16); //Max number of threads is 16 - Canvas c(-1, -1, 885, 230, "Sea Urchins!", FRAME * 2); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 885, 230, "Sea Urchins!", BLACK, nullptr, FRAME * 2); c.run(seaUrchinFunction, nthreads); } diff --git a/src/examples/ShakerSort/Makefile b/src/examples/ShakerSort/Makefile new file mode 100644 index 000000000..7a53faadf --- /dev/null +++ b/src/examples/ShakerSort/Makefile @@ -0,0 +1,87 @@ +# Makefile for ShakerSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testShakerSort + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ShakerSort/testShakerSort.cpp b/src/examples/ShakerSort/testShakerSort.cpp new file mode 100644 index 000000000..a1ca28d03 --- /dev/null +++ b/src/examples/ShakerSort/testShakerSort.cpp @@ -0,0 +1,115 @@ +/* + * testShakerSort.cpp + * + * Usage: ./testShakerSort + */ + +#include + +using namespace tsgl; + +/*! + * \brief Provides a visualization for a basic (and slow) shaker sort. + * \details + * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. + * - An integer array of size \b SIZE is allocated. + * - A flag \b goingUp is set. + * - Our integer array is filled with random integers under the Canvas' height. + * - The background color is set to gray for visibility. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - While the Canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - If the minimum sorted element is greater than or equals the maximum, we're done. + * - At a rate of \b IPF times a second: + * - If we're going up and the element above us is less than us, swap. + * - If we're going down and the element below us is less than us, swap. + * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. + * . + * - Pause the animation. + * - Clear the Canvas. + * - From 0 to \b SIZE: + * - Get the height of each element in the integer array. + * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. + * . + * - Resume the animation. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void shakerSortFunction(Canvas& can) { + const int SIZE = 550, // Size of the data pool (set to 550 by default) + IPF = 50; // Iterations per frame + Rectangle* rectangles[SIZE]; // Array to store the data + float numbers[SIZE]; // Array to store the data + int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; + float temp; + bool goingUp = true; + int canWidth = (can.getWindowWidth() > can.getDisplayWidth()) ? can.getDisplayWidth() : can.getWindowWidth(); + float start = canWidth * -.45; + float rectangleWidth = canWidth * .9 / SIZE; + for (int i = 0; i < SIZE; i++) { + rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, saferand(1,can.getWindowHeight()*.9), 0, 0, 0, RED); + numbers[i] = rectangles[i]->getHeight(); + can.add(rectangles[i]); + } + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + if (min >= max) { // We are done sorting. + // If we don't call wait(), we segfault. If we call return instead, rectangles[] doesn't get deallocated. + // return would be fine if we hadn't allocated memory in this method to which Canvas needed access. + can.wait(); + } + for (int i = 0; i < IPF; i++) { + if (goingUp) { + if (numbers[pos] > numbers[pos + 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos + 1];; + numbers[pos + 1] = temp; + lastSwap = pos; + } + if (pos >= max) { + pos = max; + max = (lastSwap < max) ? lastSwap : max - 1; + goingUp = !goingUp; + } else + pos++; + } else { + if (numbers[pos] < numbers[pos - 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos - 1]; + numbers[pos - 1] = temp; + lastSwap = pos; + } + if (pos <= min) { + pos = min; + min = (lastSwap > min) ? lastSwap : min + 1; + goingUp = !goingUp; + } else + pos--; + } + } + ColorFloat color; + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + for (int i = 0; i < SIZE; i++) { + color = (i == pos) ? YELLOW : RED; + rectangles[i]->setColor(color); + rectangles[i]->setHeight(numbers[i]); + } + can.resumeDrawing(); //Tell the Canvas it can resume drawing + } + + for (int i = 0; i < SIZE; i++) { + delete rectangles[i]; + } +} + +//Takes in command line arguments for the window width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid + w = 1300; h = 900; // If not, set the width and height to a default value + } + Canvas c(-1, -1, w, h, "Shaker Sort"); + c.run(shakerSortFunction); +} diff --git a/src/examples/SolarSystem/Makefile b/src/examples/SolarSystem/Makefile new file mode 100644 index 000000000..3b066870f --- /dev/null +++ b/src/examples/SolarSystem/Makefile @@ -0,0 +1,87 @@ +# Makefile for SolarSystem + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSolarSystem + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/SolarSystem/testSolarSystem.cpp b/src/examples/SolarSystem/testSolarSystem.cpp new file mode 100644 index 000000000..4699ecae9 --- /dev/null +++ b/src/examples/SolarSystem/testSolarSystem.cpp @@ -0,0 +1,75 @@ +/* + * testSolarSystem.cpp + * + * Usage: ./testSolarSystem + */ + +#include +#include + +using namespace tsgl; + +void ssFunction(Canvas& can) { + Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); + + mercury->setRotationPoint(0,0,0); + venus->setRotationPoint(0,0,0); + earth->setRotationPoint(0,0,0); + mars->setRotationPoint(0,0,0); + jupiter->setRotationPoint(0,0,0); + saturn->setRotationPoint(0,0,0); + saturnRings->setRotationPoint(0,0,0); + uranus->setRotationPoint(0,0,0); + neptune->setRotationPoint(0,0,0); + + can.add(sun); + can.add(mercury); + can.add(venus); + can.add(earth); + can.add(mars); + can.add(jupiter); + can.add(saturn); + can.add(saturnRings); + can.add(uranus); + can.add(neptune); + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + sun->setPitch(rotation); + mercury->setPitch(rotation * 4); + venus->setPitch(rotation * 3 / 2); + earth->setPitch(rotation); + mars->setPitch(rotation/2); + jupiter->setPitch(rotation/12); + saturn->setPitch(rotation/30); + saturnRings->setPitch(rotation/30); + uranus->setPitch(rotation/90); + neptune->setPitch(rotation/180); + rotation += 1; + } + + delete sun; + delete mercury; + delete venus; + delete earth; + delete mars; + delete jupiter; + delete saturn; + delete saturnRings; + delete uranus; + delete neptune; +} + +int main(int argc, char* argv[]) { + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Solar System", BLACK); + c.run(ssFunction); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/CubeArray.cpp b/src/examples/ThreadedArrayAddition/CubeArray.cpp new file mode 100644 index 000000000..55925b5f0 --- /dev/null +++ b/src/examples/ThreadedArrayAddition/CubeArray.cpp @@ -0,0 +1,258 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Default constructor for CubeArray. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hide it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the size of the CubeArray's Text/numbers to a new size. + * \param size The new size. + */ +void CubeArray::setTextSize(float size){ + for(Text * t : myText){ + t->setSize(size); + } +} + +/** + * \brief Changes the CubeArray's yaw by a given value. + * \param yaw The yaw to add to the CubeArray's current yaw. + */ +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +/** + * \brief Changes the CubeArray's pitch by a given value. + * \param pitch The pitch to add to the CubeArray's current pitch. + */ +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +/** + * \brief Changes the CubeArray's roll by a given value. + * \param roll The roll to add to the CubeArray's current roll. + */ +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/CubeArray.h b/src/examples/ThreadedArrayAddition/CubeArray.h new file mode 100644 index 000000000..926f9fba4 --- /dev/null +++ b/src/examples/ThreadedArrayAddition/CubeArray.h @@ -0,0 +1,72 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setTextSize(float size); + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + // Operations + CubeArray operator+ (CubeArray& c2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/Makefile b/src/examples/ThreadedArrayAddition/Makefile new file mode 100644 index 000000000..43743e40e --- /dev/null +++ b/src/examples/ThreadedArrayAddition/Makefile @@ -0,0 +1,87 @@ +# Makefile for ThreadedArrayAddition + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayAddition + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp b/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp new file mode 100644 index 000000000..ef5d39934 --- /dev/null +++ b/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp @@ -0,0 +1,228 @@ +/* + * testThreadedArrayAddition.cpp + * + * Usage: ./testThreadedArrayAddition [threadingType] [numberOfThreads] [sizeOfArrays] + threadingType = 0 (slices) or 1 (chunks), defaults to 0 + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArrays <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 49 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_A_Y TITLE_Y - 125.0 // y-coordinate for Array 1 blocks +#define ARRAY_B_Y TITLE_Y - (2 * 125.0) // y-coordinate for Array 2 blocks +#define ARRAY_C_Y TITLE_Y - (3 * 125.0) // y-coordinate for Array 3 blocks +#define CUBE_Z 0.0 // z-coordinate for all Cube objects +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 25 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + Cube* myArrayABlock; + Cube* myArrayBBlock; + Cube* myArrayCBlock; +public: + // Constructor + ThreadData(unsigned tid, ColorFloat color, Cube* arrayABlock, Cube* arrayBBlock, Cube* arrayCBlock){ + threadID = tid; + myColor = color; + myArrayABlock = arrayABlock; + myArrayBBlock = arrayBBlock; + myArrayCBlock = arrayCBlock; + } + // Runs the animation for threaded array addition process + void runAddition(Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // get value from arrayA + myArrayABlock->setColor(myColor); + can.sleepFor(sleepTime); + + // get value from arrayB + myArrayBBlock->setColor(myColor); + can.sleepFor(sleepTime); + + // enter sum into arrayC + myArrayCBlock->setColor(myColor); + } +}; + + +void arrayFunction(Canvas& can, int threadingType, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to sum + int numArrayA[arraySize]; + int numArrayB[arraySize]; + int numArrayC[arraySize]; + + // Fill numerical arrays A and B with random numbers between 0 and 49 + for(unsigned i = 0; i < arraySize; i++){ + numArrayA[i] = (rand() % (RAND_UPPER+1)); + numArrayB[i] = (rand() % (RAND_UPPER+1)); + } + + // Create 3D arrays + CubeArray arrayA(0, ARRAY_A_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayA, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + CubeArray arrayB(0, ARRAY_B_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayB, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + CubeArray arrayC(0, ARRAY_C_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayC, 0, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * arrayALabel = new Text(arrayA.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_A_Y, TEXT_Z, + L"a", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * arrayBLabel = new Text(arrayB.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_B_Y, TEXT_Z, + L"b", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * arrayCLabel = new Text(arrayC.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_C_Y, TEXT_Z, + L"c", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Addition: c[i] = a[i] + b[i]", FONT, FONT_SIZE + 20, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {arrayALabel, arrayBLabel, arrayCLabel, titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + arrayB.draw(can); + arrayC.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.5; // initial number of seconds to sleep + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0 and threadingType == 0){ + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + numArrayC[i] = numArrayA[i] + numArrayB[i]; + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i), arrayB.getCube(i), + arrayC.getCube(i)); + td->runAddition(can, sleepTime); + arrayC[i] = numArrayC[i]; + arrayC.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + complete = 1; + } + if(complete == 0 and threadingType == 1){ + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static, 1) + for(unsigned i = 0; i < arraySize; i++){ + + numArrayC[i] = numArrayA[i] + numArrayB[i]; + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i), arrayB.getCube(i), + arrayC.getCube(i)); + td->runAddition(can, sleepTime); + arrayC[i] = numArrayC[i]; + arrayC.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + complete = 1; + } + } + + // Output + printf("\nAdded two arrays of size %d using %d threads\n", arraySize, numThreads); + printf("\nArray A: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayA[i]); + } + printf("\nArray B: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayB[i]); + } + printf("\nArray C: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayC[i]); + } + printf("\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + +} + +int main(int argc, char* argv[]){ + int threadingType = (argc > 1) ? atoi(argv[1]) : 0; + int numberOfThreads = (argc >2) ? atoi(argv[2]) : 4; + int sizeOfArrays = (argc > 3) ? atoi(argv[3]) : 10; + + // Checks validity of threadingType, numThreads, and sizeOfArrays; if one is invalid, set all to default + if((threadingType < 0 or threadingType > 1) or (sizeOfArrays <= 0 or sizeOfArrays > 24) or + (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayAddition [threadingType] [numberOfThreads] [sizeOfArrays]\n \ + threadingType = 0 (slices) or 1 (chunks)\n \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArrays <= 24\ + \nUsing default parameters...\n"); + threadingType = 0; + numberOfThreads = 4; + sizeOfArrays = 10; + } + + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Threaded Array Addition", BLACK); + c.run(arrayFunction, threadingType, numberOfThreads, sizeOfArrays); +} diff --git a/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp b/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp new file mode 100644 index 000000000..55925b5f0 --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp @@ -0,0 +1,258 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Default constructor for CubeArray. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hide it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the size of the CubeArray's Text/numbers to a new size. + * \param size The new size. + */ +void CubeArray::setTextSize(float size){ + for(Text * t : myText){ + t->setSize(size); + } +} + +/** + * \brief Changes the CubeArray's yaw by a given value. + * \param yaw The yaw to add to the CubeArray's current yaw. + */ +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +/** + * \brief Changes the CubeArray's pitch by a given value. + * \param pitch The pitch to add to the CubeArray's current pitch. + */ +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +/** + * \brief Changes the CubeArray's roll by a given value. + * \param roll The roll to add to the CubeArray's current roll. + */ +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/CubeArray.h b/src/examples/ThreadedArrayBubbleSort/CubeArray.h new file mode 100644 index 000000000..926f9fba4 --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/CubeArray.h @@ -0,0 +1,72 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setTextSize(float size); + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + // Operations + CubeArray operator+ (CubeArray& c2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/Makefile b/src/examples/ThreadedArrayBubbleSort/Makefile new file mode 100644 index 000000000..6327c08de --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/Makefile @@ -0,0 +1,87 @@ +# Makefile for ThreadedArrayBubbleSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayBubbleSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp b/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp new file mode 100644 index 000000000..7dc6c5e8d --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp @@ -0,0 +1,210 @@ +/* + * testArrayBubbleSort.cpp + * + * Usage: ./testThreadedArrayBubbleSort [numberOfThreads] [sizeOfArrays] + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArrays <= 24, defaults to 10 + */ + +#include +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + unsigned myIndex; +public: + // Constructor + ThreadData(unsigned tid, ColorFloat color, unsigned index){ + threadID = tid; + myColor = color; + myIndex = index; + } + + // Swaps the positions of two values in the array + void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; + } + + // Runs the sorting and animation for threaded array bubble sort process + void runSort(CubeArray& arr, Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // Get value from first block + arr.getCube(myIndex)->setColor(myColor); + // Get value from second block + arr.getCube(myIndex+1)->setColor(myColor); + can.sleepFor(sleepTime); + + // Compare values + if(arr[myIndex] > arr[myIndex+1]){ + swap(arr[myIndex], arr[myIndex+1]); + arr.update(myIndex); arr.update(myIndex+1); + } + can.sleepFor(sleepTime); + + // Leave blocks + arr.getCube(myIndex)->setColor(ARRAY_COLOR); + arr.getCube(myIndex+1)->setColor(ARRAY_COLOR); + } +}; + +void sortVisualizationFunction(Canvas& can, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int originalArray[arraySize]; + // int sortedArray[] = {40, 35, 80, 62, 60, 74, 36, 10, 19, 5}; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = rand() % (RAND_UPPER + 1); + // originalArray[i] = i + 90; + } + + printf("Before bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Bubble Sort in Parallel", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + // Text * speedLabel = new Text(0.0, ARRAY_Y - 100.0, TEXT_Z, + // "Speed: x" + std::to_string(sleepTime/250000), FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.125; // initial number of seconds to sleep 0.5 + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0){ + // Parallel bubble sort + for(int i = 0; i < arrayA.getSize(); i++){ + int first = i%2; + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned j = first; j < arraySize - 1; j+=2){ + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], j); + td->runSort(arrayA, can, sleepTime); + delete td; + } + } + //******************************************************************** + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\nSorted array of size %d using %d threads.\n", arraySize, numThreads); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int numberOfThreads = (argc >1) ? atoi(argv[1]) : 4; + int sizeOfArrays = (argc > 2) ? atoi(argv[2]) : 10; + + // Checks validity of numThreads and sizeOfArrays; if one is invalid, set all to default + if((sizeOfArrays <= 0 or sizeOfArrays > 24) or (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayBubbleSort [numberOfThreads] [sizeOfArrays]\n \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArrays <= 24\ + \nUsing default parameters...\n"); + numberOfThreads = 4; + sizeOfArrays = 10; + } + + printf("Use the up and down arrow keys to speed up and slow down the animation, respectively.\n"); + + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Threaded Array Bubble Sort", BLACK); + c.run(sortVisualizationFunction, numberOfThreads, sizeOfArrays); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/CubeArray.cpp b/src/examples/ThreadedArrayOperations/CubeArray.cpp new file mode 100644 index 000000000..55925b5f0 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/CubeArray.cpp @@ -0,0 +1,258 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Default constructor for CubeArray. + * \details This is the default constructor for the CubeArray class. + * \return A new CubeArray with a default size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hide it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the size of the CubeArray's Text/numbers to a new size. + * \param size The new size. + */ +void CubeArray::setTextSize(float size){ + for(Text * t : myText){ + t->setSize(size); + } +} + +/** + * \brief Changes the CubeArray's yaw by a given value. + * \param yaw The yaw to add to the CubeArray's current yaw. + */ +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +/** + * \brief Changes the CubeArray's pitch by a given value. + * \param pitch The pitch to add to the CubeArray's current pitch. + */ +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +/** + * \brief Changes the CubeArray's roll by a given value. + * \param roll The roll to add to the CubeArray's current roll. + */ +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/CubeArray.h b/src/examples/ThreadedArrayOperations/CubeArray.h new file mode 100644 index 000000000..926f9fba4 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/CubeArray.h @@ -0,0 +1,72 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setTextSize(float size); + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + // Operations + CubeArray operator+ (CubeArray& c2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/Makefile b/src/examples/ThreadedArrayOperations/Makefile new file mode 100644 index 000000000..68a14fb68 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/Makefile @@ -0,0 +1,87 @@ +# Makefile for ThreadedArrayOperations + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayOperations + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp b/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp new file mode 100644 index 000000000..92e365e55 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp @@ -0,0 +1,240 @@ +/* + * testThreadedArrayOperations.cpp + * + * Usage: ./testThreadedArrayOperations [operation] [numberOfThreads] [sizeOfArray] + operation = 0 (addition), 1 (multiplication), or 2 (exponentiation), defaults to 0 + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 9 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + Cube* myArrayBlock; +public: + ThreadData(unsigned tid, ColorFloat color, Cube* arrayBlock){ + threadID = tid; + myColor = color; + myArrayBlock = arrayBlock; + } + // Runs the animation for threaded array addition processe + void runAnimation(Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // get value from array + myArrayBlock->setColor(myColor); + can.sleepFor(sleepTime); + } +}; + +void operationVisualization(Canvas& can, int operation, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int numArray[arraySize]; + + // Fill numerical array with random numbers between 0 and 9 + for(unsigned i = 0; i < arraySize; i++){ + numArray[i] = (rand() % (RAND_UPPER+1)); + } + + // Create 3D arrays + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, numArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * arrayALabel = new Text(arrayA.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_Y, TEXT_Z, + L"a", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Scalar Operations: a +/*/^ n", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * operationNumLabel = new Text(0.0, TITLE_Y-50, TEXT_Z, + L"n = 0", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {arrayALabel, titleLabel, operationNumLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.5; // initial number of seconds to sleep + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + // ADDITION + if(complete == 0 and operation == 0){ + // Generate random number to add (0 - 990) + int operationNum = rand() % 991; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a + n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = arrayA[i] + operationNum; + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nAdded %d to array of size %d using %d threads\n", operationNum, arraySize, numThreads); + complete = 1; + } + + // MULTIPLICATION + if(complete == 0 and operation == 1){ + // Generate random number to mulitply by (1 - 111) + int operationNum = (rand() % 111) + 1; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a * n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = arrayA[i] * operationNum; + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nMultiplied array of size %d by %d using %d threads\n", arraySize, operationNum, numThreads); + complete = 1; + } + + // EXPONENTIATION + if(complete == 0 and operation == 2){ + // Generate random number to exponentiate by (2 - 3) + unsigned int operationNum = (rand() % 2) + 2; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a^n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = pow(arrayA[i], operationNum); + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nExponentiated array of size %d by %d using %d threads\n", arraySize, operationNum, numThreads); + complete = 1; + } + } + + // Output + printf("Before scalar operation: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArray[i]); + } + printf("\nAfter scalar operation: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + +} + +int main(int argc, char* argv[]){ + int operation = (argc > 1) ? atoi(argv[1]) : 0; + int numberOfThreads = (argc >2) ? atoi(argv[2]) : 4; + int sizeOfArray = (argc > 3) ? atoi(argv[3]) : 10; + + // Checks validity of operation, numThreads, and sizeOfArray; if one is invalid, set all to default + if((operation < 0 or operation > 2) or (sizeOfArray <= 0 or sizeOfArray > 24) or + (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayOperations [operation] [numberOfThreads] [sizeOfArray]\n \ + operation = 0 (addition), 1 (multiplication), or 2 (exponentiation), defaults to 0 \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + operation = 0; + numberOfThreads = 4; + sizeOfArray = 10; + } + + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Threaded Array Scalar Operations", BLACK); + c.run(operationVisualization, operation, numberOfThreads, sizeOfArray); +} diff --git a/src/examples/ThreadedSolarSystem/Makefile b/src/examples/ThreadedSolarSystem/Makefile new file mode 100644 index 000000000..bd69d01eb --- /dev/null +++ b/src/examples/ThreadedSolarSystem/Makefile @@ -0,0 +1,87 @@ +# Makefile for ThreadedSolarSystem + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedSolarSystem + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp b/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp new file mode 100644 index 000000000..43bc78cb0 --- /dev/null +++ b/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp @@ -0,0 +1,102 @@ +/* + * testThreadedSolarSystem.cpp + * + * Usage: ./testThreadedSolarSystem + */ + +#include +#include +#include + +using namespace tsgl; + +class ThreadData{ +private: + unsigned myThreadID; + Drawable * myPlanet; // the Drawable object the thread is responsible for + float myPitchDelta; + +public: + ThreadData(unsigned tid, Drawable * object, float pitch){ + myThreadID = tid; + myPlanet = object; + myPitchDelta = pitch; + } + + void changePitch(){ + myPlanet->changePitchBy(myPitchDelta); + } +}; + + +void ssFunction(Canvas& can) { + Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); + + // saturnRings->displayOutlineEdges(false); + + mercury->setRotationPoint(0,0,0); + venus->setRotationPoint(0,0,0); + earth->setRotationPoint(0,0,0); + mars->setRotationPoint(0,0,0); + jupiter->setRotationPoint(0,0,0); + saturn->setRotationPoint(0,0,0); + saturnRings->setRotationPoint(0,0,0); + uranus->setRotationPoint(0,0,0); + neptune->setRotationPoint(0,0,0); + + // Items in planetArray have the same index as their corresponding rotation speeds in rotationArray + Drawable * planetArray[] = {mercury, venus, earth, mars, jupiter, saturn, saturnRings, uranus, neptune}; + float rotationArray[] = {4.0, 3.0/2.0, 1.0, 1.0/2.0, 1.0/12.0, 1.0/30.0, 1.0/30.0, 1.0/90.0, 1.0/180.0}; + + can.add(sun); + can.add(mercury); + can.add(venus); + can.add(earth); + can.add(mars); + can.add(jupiter); + can.add(saturn); + can.add(saturnRings); + can.add(uranus); + can.add(neptune); + + while (can.isOpen()) { + can.sleep(); + #pragma omp parallel + { + unsigned tid = omp_get_thread_num(); + unsigned numThreads = omp_get_num_threads(); + + for(unsigned i = tid; i < 9; i += numThreads){ + ThreadData * td = new ThreadData(tid, planetArray[i], rotationArray[i]); + // printf("Thread %d out of %d running planet %d\n", + // tid, numThreads - 1, i); + td->changePitch(); + } + } + } + + delete sun; + delete mercury; + delete venus; + delete earth; + delete mars; + delete jupiter; + delete saturn; + delete saturnRings; + delete uranus; + delete neptune; +} + +int main(int argc, char* argv[]) { + Canvas c(0, -1, Canvas::getDisplayWidth(), 620, "Solar System", BLACK); + c.run(ssFunction); +} \ No newline at end of file diff --git a/src/examples/Voronoi/Makefile b/src/examples/Voronoi/Makefile new file mode 100644 index 000000000..983122622 --- /dev/null +++ b/src/examples/Voronoi/Makefile @@ -0,0 +1,87 @@ +# Makefile for Voronoi + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testVoronoi + +# Object files +ODIR = obj +_OBJ = ShadedVoronoi.o Voronoi.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/Voronoi/ShadedVoronoi.cpp b/src/examples/Voronoi/ShadedVoronoi.cpp similarity index 74% rename from src/tests/Voronoi/ShadedVoronoi.cpp rename to src/examples/Voronoi/ShadedVoronoi.cpp index 167f36de6..5c322818c 100644 --- a/src/tests/Voronoi/ShadedVoronoi.cpp +++ b/src/examples/Voronoi/ShadedVoronoi.cpp @@ -13,11 +13,12 @@ ShadedVoronoi::ShadedVoronoi(Canvas& can) : Voronoi(can) { } void ShadedVoronoi::draw(Canvas& can) { + Background * bg = can.getBackground(); const int WW = can.getWindowWidth(), // Set the screen sizes WH = can.getWindowHeight(); #pragma omp parallel for - for (int i = 0; i < WW; i++) { // For each individual point... - for (int j = 0; j < WH; j++) { + for (int i = -WW/2; i < WW/2; i++) { // For each individual point... + for (int j = -WH/2; j < WH/2; j++) { int myBestK = -1, myNextBestK = -1; float myBDist = 9999, myNBDist = 9999; // Reset the best distance for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point @@ -33,16 +34,16 @@ void ShadedVoronoi::draw(Canvas& can) { myNextBestK = k; } } - myKValue[i * WH + j] = myBestK; - myKValue2[i * WH + j] = myNextBestK; - can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color + myKValue[(i + WW/2) * WH + (j + WH/2)] = myBestK; + myKValue2[(i + WW/2) * WH + (j + WH/2)] = myNextBestK; + bg->drawPixel(i, j, myColor[myBestK]); // Draw the point with the closest control's color } } #pragma omp parallel for - for (int i = 0; i < WW; i++) { // For each individual point... - for (int j = 0; j < WH; j++) { - int k = myKValue[i * WH + j]; // Find its closest control point - int nk = myKValue2[i * WH + j]; // Then find its second closest + for (int i = -WW/2; i < WW/2; i++) { // For each individual point... + for (int j = -WH/2; j < WH/2; j++) { + int k = myKValue[(i + WW/2) * WH + (j+WH/2)]; // Find its closest control point + int nk = myKValue2[(i + WW/2) * WH + (j+WH/2)]; // Then find its second closest float xd1 = i - myX[k]; float yd1 = j - myY[k]; float d1 = xd1 * xd1 + yd1 * yd1; // Find the distance to it closest @@ -51,7 +52,7 @@ void ShadedVoronoi::draw(Canvas& can) { float kd = xkd * xkd + ykd * ykd; // Find the distance between the CPs themselves float shading = sqrt(d1 / kd); clamp(shading,0,1); - can.drawPoint(i, j, ColorFloat(0, 0, 0, shading)); // Draw the point with the closest control's color + bg->drawPixel(i, j, ColorFloat(0, 0, 0, shading)); // Draw the point with the closest control's color } } } diff --git a/src/tests/Voronoi/ShadedVoronoi.h b/src/examples/Voronoi/ShadedVoronoi.h similarity index 100% rename from src/tests/Voronoi/ShadedVoronoi.h rename to src/examples/Voronoi/ShadedVoronoi.h diff --git a/src/tests/Voronoi/Voronoi.cpp b/src/examples/Voronoi/Voronoi.cpp similarity index 74% rename from src/tests/Voronoi/Voronoi.cpp rename to src/examples/Voronoi/Voronoi.cpp index c1f6c6bc5..1981bd13c 100644 --- a/src/tests/Voronoi/Voronoi.cpp +++ b/src/examples/Voronoi/Voronoi.cpp @@ -9,22 +9,22 @@ using namespace tsgl; Voronoi::Voronoi(Canvas& can) { const int WW = can.getWindowWidth(), // Set the screen sizes WH = can.getWindowHeight(); - srand(time(NULL)); + // srand(time(NULL)); myX = new int[MY_POINTS](); myY = new int[MY_POINTS](); myKValue = new int[WW * WH](); for (int i = 0; i < MY_POINTS; i++) { // Randomize the control points - myX[i] = rand() % WW; - myY[i] = rand() % WH; + myX[i] = saferand(-WW/2, WW/2); + myY[i] = saferand(-WH/2, WH/2); } - srand(time(NULL)); + // srand(time(NULL)); myTC = Colors::randomColor(1.0f); // Randomize the axis colors myRC = Colors::randomColor(1.0f); myLC = Colors::randomColor(1.0f); myBC = Colors::randomColor(1.0f); for (int j = 0; j < MY_POINTS; j++) { // For each control point... - float xx = (float) myX[j] / WW; // Calculate an value from 0:1 based on x coord - float yy = (float) myY[j] / WH; // Do the same for y + float xx = (float) myX[j] / WW + 0.5; // Calculate an value from 0:1 based on x coord + float yy = (float) myY[j] / WH + 0.5; // Do the same for y myXC = Colors::blend(myLC, myRC, xx); // Interpolate between the left and right colors myYC = Colors::blend(myTC, myBC, yy); // Do the same for top and bottom myColor[j] = Colors::blend(myXC, myYC, 0.5f); // Complete the 4-way interpolation @@ -33,12 +33,15 @@ Voronoi::Voronoi(Canvas& can) { } void Voronoi::draw(Canvas& can) { + const int WW = can.getWindowWidth(), // Set the screen sizes + WH = can.getWindowHeight(); + Background * bg = can.getBackground(); int myBestK = 0; // Keep track of the current best k-value float myBDist, myDist, myXD, myYD; // Keep track of the closes matches and current distances #pragma omp parallel for private(myBDist, myXD, myYD, myDist, myBestK) - for (int i = 0; i < can.getWindowWidth(); i++) { // For each individual point... + for (int i = -WW/2; i < WW/2; i++) { // For each individual point... myBestK = 0; - for (int j = 0; j < can.getWindowHeight(); j++) { + for (int j = -WH/2; j < WH/2; j++) { myBDist = 9999; // Reset the best distance for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point myXD = i - myX[k]; // Calculate the distance from each control point @@ -49,8 +52,8 @@ void Voronoi::draw(Canvas& can) { myBestK = k; } } - myKValue[i * can.getWindowHeight() + j] = myBestK; - can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color + myKValue[(i + WW/2) * WH + (j + WH/2)] = myBestK; + bg->drawPixel(i, j, myColor[myBestK]); // Draw the point with the closest control's color if (!can.isOpen()) break; } } diff --git a/src/tests/Voronoi/Voronoi.h b/src/examples/Voronoi/Voronoi.h similarity index 100% rename from src/tests/Voronoi/Voronoi.h rename to src/examples/Voronoi/Voronoi.h diff --git a/src/tests/testVoronoi.cpp b/src/examples/Voronoi/testVoronoi.cpp similarity index 98% rename from src/tests/testVoronoi.cpp rename to src/examples/Voronoi/testVoronoi.cpp index d0a05d6e9..5015fa227 100644 --- a/src/tests/testVoronoi.cpp +++ b/src/examples/Voronoi/testVoronoi.cpp @@ -6,8 +6,8 @@ /* testVoronoi.cpp contains multiple functions that display a Voronoi diagram in similar fashions. */ -#include "Voronoi/Voronoi.h" -#include "Voronoi/ShadedVoronoi.h" +#include "Voronoi.h" +#include "ShadedVoronoi.h" using namespace tsgl; diff --git a/src/tests/DiningPhilosophers/Fork.h b/src/tests/DiningPhilosophers/Fork.h deleted file mode 100644 index 53e136095..000000000 --- a/src/tests/DiningPhilosophers/Fork.h +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * \struct Fork - * \brief Struct for the forks in the Dining Philosophers' problem - */ - -#ifndef FORK_H_ -#define FORK_H_ - -#include -using namespace tsgl; - -struct Fork { - int user, id; - ConcavePolygon * myShape; - Fork() { - user = -1; id = 0; - - const int POINTS = 20; // number of vertices in polygon - const int HEIGHT = 42; // 42 is preferred, but can be changed - const int WIDTH = 12; // 12 is preferred, but can be changed - int xs[POINTS], ys[POINTS]; - - // scales (out of 100) for the dimensions of the fork - double xscale[POINTS] = {0, 19, 19, 27, 27, 46, 46, 54, 54, 73, 73, 81, 81, 100, 100, 65, 65, 35, 35, 0}; - double yscale[POINTS] = {0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 30, 30, 100, 100, 30, 30}; - - // create the fork points from the scale arrays - for(int i = 0; i < POINTS; ++i) { - // scale the fork - xs[i] = WIDTH * xscale[i]; - ys[i] = HEIGHT * yscale[i]; - xs[i] = xs[i]/100; - ys[i] = ys[i]/100; - } - - //Add vertices - myShape = new ConcavePolygon(POINTS, xs, ys, BLACK, BLACK); - } - void setCanvas( Canvas* can) { - can->add(myShape); - } - void draw(int x, int y, double angle, ColorFloat c) { - angle -= PI/2; - myShape->setColor(c, (c.asString() != "0R,0G,0B,1A")? BLACK : DARKGRAY); - myShape->setCenter(x, y); - myShape->setRotation(angle); - } - ~Fork() { - delete myShape; - } -}; - -#endif /* FORK_H_ */ \ No newline at end of file diff --git a/src/tests/Makefile b/src/tests/Makefile new file mode 100644 index 000000000..6695bfe9e --- /dev/null +++ b/src/tests/Makefile @@ -0,0 +1,83 @@ +# Master Makefile for Tests + +# ***************************************************** + +# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the tests +SUBDIRS_TO_BUILD := test2Dvs3D \ + test3DRotation \ + testAlphaRectangle \ + testArrows \ + testAura \ + testBackground \ + testBlurImage \ + testCalcPi \ + testCamera \ + testCircle \ + testColorWheel \ + testConcavePolygon \ + testCone \ + testConvexPolygon \ + testCosineIntegral \ + testCube \ + testCuboid \ + testCylinder \ + testDiorama \ + testEllipse \ + testEllipsoid \ + testFunction \ + testGetColors \ + testGetPixels \ + testGradientWheel \ + testGraydient \ + testGreyscale \ + testHighData \ + testImage \ + testImageCart \ + testInverter \ + testLineChain \ + testLineFan \ + testLines \ + testMouse \ + testPixels \ + testPrism \ + testProcedural \ + testProgressBar \ + testProjectiles \ + testPyramid \ + testRectangle \ + testRegularPolygon \ + testScreenshot \ + testSpectrogram \ + testSpectrum \ + testSphere \ + testSquare \ + testStar \ + testText \ + testTextCart \ + testTextTwo \ + testTransparency \ + testTriangle \ + testTriangleStrip \ +# test_specs \ +# testDice \ +# testUnits \ + +SUBDIRS_TO_CLEAN := $(subst test,..., $(SUBDIRS_TO_BUILD)) # Used to clean the tests + + +all: $(SUBDIRS_TO_BUILD) + +$(SUBDIRS_TO_BUILD): + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" + @tput sgr0; + @echo "" + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) + +clean: $(SUBDIRS_TO_CLEAN) + +$(SUBDIRS_TO_CLEAN): + cd $(subst ...,test,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/tests/Pong/Paddle.cpp b/src/tests/Pong/Paddle.cpp deleted file mode 100644 index 008f66b21..000000000 --- a/src/tests/Pong/Paddle.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Paddle.cpp - */ - -#include "Paddle.h" - - /*! - * \brief Explicitly constructs a Paddle object. - * \details Explicit constructor for a Paddle object. - * \param can Reference to the Canvas to have the Paddle object on. - * \param speed Reference to the speed of the Paddle object. - * \return The constructed Paddle object. - */ -Paddle::Paddle(Canvas& can, int & speed, int side) { - mySpeed = speed; - myDir = myPoints = 0; - myY = can.getWindowHeight() / 2 - 32; - myRect = new Rectangle(0,0,24,64, BLACK); - if(side == -1) { //Left side - myRect->setColor(BLUE); - myRect->setCenter(20, myY); - } else if(side == 1) { //Right side - myRect->setColor(RED); - myRect->setCenter(can.getWindowWidth() - 20, myY); - } - can.add(myRect); -} - - /*! - * \brief Binds the buttons. - * \details Binds the buttons with the Canvas. In this case, the keys that move the paddle up and down. - * \param can Reference to the Canvas to bind the keys to. - * \param side The side that the Paddle object is on (left = -1 and the W and S keys are bound, right = 1 and the Up and Down arrow keys are bound). - */ -void Paddle::bindings(Canvas& can, int side) { - if(side == 1) { //Right - can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = -1;}); - can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = 1;}); - can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); - can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); - } else if(side == -1) { //Left - can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = -1;}); - can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = 1;}); - can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); - can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); - } -} - - /*! - * \brief Draw the Paddle object. - * \details Actually draws the Paddle object onto the Canvas. - * \param can Reference to the Canvas to draw on. - * \param side The side that the Paddle object is drawn to on the Canvas (left = -1, right = 1). - */ -void Paddle::draw(Canvas& can, int side) { - if(side == -1) { //Left side - // ColorFloat color[4]; - // for (unsigned i = 0; i < 4; ++i) { - // color[i] = Colors::randomColor(1.0f); - // } - can.drawRectangle(8, myY, 32, myY + 64, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f) /* color */, false); - } else if(side == 1) { //Right side - can.drawRectangle(can.getWindowWidth() - 24 - 8, myY, can.getWindowWidth() - 8, myY + 64, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f), true); - } -} - - /*! - * \brief Increments the Paddle object's score in the game of Pong. - */ -void Paddle::increment() { - ++myPoints; -} - - /*! - * \brief Actually Moves the Paddle object up or down. - */ -void Paddle::move() { - myY += mySpeed * myDir; - myRect->moveShapeBy(0, mySpeed * myDir); -} - - /*! - * \brief Accessor for the score of the Paddle object. - * \return myPoints The current score of the Paddle object in the game of Pong. - */ -int Paddle::getPoints() const { - return myPoints; -} - - /*! - * \brief Accessor for the current y-coordinate of the Paddle object. - * \return myY The y-coordinate of the Paddle object. - */ -float Paddle::getY() const { - return myY; -} - - /*! - * \brief Mutator for the direction of the Paddle object. - * \details Changes the current direction of the Paddle object (up or down). - */ -void Paddle::setDir(int direction) { - myDir = direction; -} diff --git a/src/tests/Pong/Pong.cpp b/src/tests/Pong/Pong.cpp deleted file mode 100644 index 32d9e2603..000000000 --- a/src/tests/Pong/Pong.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Pong.cpp - */ - -#include "Pong.h" - -using namespace tsgl; - - /*! - * \brief Explicitly construct the game, Pong. - * \details Explicit constructor for the game, Pong. It sets up the Paddle objects and the Ball object - * in order to play. - * \param can Reference to the Canvas to use when playing Pong. - * \param ballSpeed Reference to the ball speed to use in the game. - * \param paddleSpeed Reference to the paddle speed to use in the game. - */ -Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { - leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object - rightPaddle = new Paddle(can, paddleSpeed, 1); - srand(time(NULL)); - //Bind the buttons - leftPaddle->bindings(can, -1); // W & S keys - rightPaddle->bindings(can, 1); // Up and Down arrow keys - pongBall = new Ball(can, ballSpeed); - leftScore = new Text(L"0", can.getWindowWidth() / 2-64, 40, 32, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); - rightScore = new Text(L"0", can.getWindowWidth()/2+64, 40, 32, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); - can.add(leftScore); can.add(rightScore); -} - - /*! - * \brief Draw the game of Pong. - * \details Actually draws all of the necessary components in order to play Pong. - * This also includes any necessary button bindings in order to move the Paddle objects. - * \param can Reference to the Canvas to draw on. - * \see Paddle class, Ball class. - */ -void Pong::draw(Canvas& can) { - // While the window has not been closed.... - while (can.isOpen()) { - can.sleep(); - // Move the ball - pongBall->move(); - // Handle ball boundary collisions - if (pongBall->getX() > can.getWindowWidth() + 8) { - leftPaddle->increment(); // Increment the points - leftScore->setText( std::to_wstring(leftPaddle->getPoints())); - pongBall->reset(can); // Reset the ball's position - } else if (pongBall->getX() < -8) { - rightPaddle->increment(); - rightScore->setText( std::to_wstring(rightPaddle->getPoints())); - pongBall->reset(can); - } else if (pongBall->getY() > can.getWindowHeight() - 8 || pongBall->getY() < 8) pongBall->invert(0); //Invert the ball's y-coordinate changer - // Handle ball paddle collisions - // handle left - if (pongBall->getX() - 8 < 32 && - pongBall->getX() - 8 > 16 && - pongBall->getY() > leftPaddle->getY() - 32&& - pongBall->getY() < leftPaddle->getY() + 32) - { - pongBall->invert(1); - } - // handle right - else if (pongBall->getX() + 8 > can.getWindowWidth() - 32 && - pongBall->getX() + 8 < can.getWindowWidth() - 16 && - pongBall->getY() > rightPaddle->getY() - 32 && - pongBall->getY() < rightPaddle->getY() + 32) - { - pongBall->invert(1); - } - // Move the paddles if necessary - leftPaddle->move(); - rightPaddle->move(); - } -} - -/** - * \brief Destroys the Pong game object. - */ -Pong::~Pong() { - delete pongBall; - delete leftPaddle; - delete rightPaddle; - delete leftScore; - delete rightScore; -} \ No newline at end of file diff --git a/src/tests/SeaUrchin/SeaUrchin.cpp b/src/tests/SeaUrchin/SeaUrchin.cpp deleted file mode 100644 index 388b5383c..000000000 --- a/src/tests/SeaUrchin/SeaUrchin.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SeaUrchin.cpp - */ - -#include "SeaUrchin.h" - -SeaUrchin::SeaUrchin(Canvas& can, int threadId) { - myOldX = myOldY = 50; - myOldX += (threadId % 8) * 110; - myOldY += (threadId / 8) * 110; - myNewX = myNewY = 0; - myColor = Colors::highContrastColor(threadId); - for(int i = 0; i < MY_SPOKES; i++) { - Line * l = new Line(myOldX, myOldY, myNewX, myNewY, myColor); - lines.push_back(l); - can.add(l); - } -} - -void SeaUrchin::move(Canvas& can) { - float delta = (2.0f / MY_SPOKES) * PI; - for(int j = 0; j < MY_SPOKES; ++j) { - myNewX = myOldX + 50 * cos(j * delta + can.getReps()); - myNewY = myOldY + 50 * sin(j * delta + can.getReps()); - lines[j]->setFirstEnd(myOldX, myOldY); - lines[j]->setSecondEnd(myNewX, myNewY); - } -} - -SeaUrchin::~SeaUrchin() { - for (unsigned int i = 0; i < lines.size(); i++) { - delete lines[i]; - } -} - diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile new file mode 100644 index 000000000..cf11c9c80 --- /dev/null +++ b/src/tests/test2Dvs3D/Makefile @@ -0,0 +1,87 @@ +# Makefile for test2Dvs3D + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test2Dvs3D + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp new file mode 100644 index 000000000..2c47d5f79 --- /dev/null +++ b/src/tests/test2Dvs3D/test2Dvs3D.cpp @@ -0,0 +1,96 @@ +/* + * test2Dvs3D.cpp + * + * Usage: ./test2Dvs3D + */ + +#include +#include + +using namespace tsgl; + +void contrastFunction(Canvas& can) { + ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; + ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; + ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; + Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); + // can.add(testPyramid); + Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); + // can.add(triangle1); + Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); + // can.add(triangle2); + Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); + // can.add(triangle3); + Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); + // can.add(triangle4); + Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); + // can.add(triangle5); + Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); + // can.add(triangle6); + // testPyramid->setPitch(45); + int stepsTaken = 0; + while (can.isOpen()) { + can.sleep(); + if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { + can.add(triangle1); + stepsTaken++; + } + if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { + can.add(triangle2); + stepsTaken++; + } + if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { + can.add(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { + can.add(testPyramid); + stepsTaken++; + } + if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { + can.remove(triangle1); + can.remove(triangle2); + can.remove(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { + can.add(triangle4); + stepsTaken++; + } + if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { + can.add(triangle5); + stepsTaken++; + } + if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { + can.add(triangle6); + stepsTaken++; + } + if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { + if (testPyramid->getPitch() < 45) { + testPyramid->changePitchBy(0.5); + } else { + testPyramid->setPitch(45); + stepsTaken++; + } + } + } + + delete testPyramid; + delete triangle1; + delete triangle2; + delete triangle3; + delete triangle4; + delete triangle5; + delete triangle6; + +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing", BLACK); + c.run(contrastFunction); +} \ No newline at end of file diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile new file mode 100644 index 000000000..39adc56fe --- /dev/null +++ b/src/tests/test3DRotation/Makefile @@ -0,0 +1,87 @@ +# Makefile for test3DRotation + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test3DRotation + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test3DRotation/test3DRotation.cpp b/src/tests/test3DRotation/test3DRotation.cpp new file mode 100644 index 000000000..1ed4e77bd --- /dev/null +++ b/src/tests/test3DRotation/test3DRotation.cpp @@ -0,0 +1,48 @@ +/* + * test3DRotation.cpp + * + * Usage: ./test3DRotation + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); + testCube->setRotationPoint(0,0,0); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); + Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + can.add(testCube); + can.add(testPrism); + can.add(testSphere); + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + testCube->setYaw(rotation); + testPrism->setYaw(-rotation); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setYaw(-rotation); + rotation += 1; + } + + delete testCube; + delete testPrism; + delete testSphere; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Rotation", BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile new file mode 100644 index 000000000..feb61586c --- /dev/null +++ b/src/tests/testAlphaRectangle/Makefile @@ -0,0 +1,87 @@ +# Makefile for testAlphaRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAlphaRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAlphaRectangle.cpp b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp similarity index 78% rename from src/tests/testAlphaRectangle.cpp rename to src/tests/testAlphaRectangle/testAlphaRectangle.cpp index 4340864e4..8721ee1ea 100644 --- a/src/tests/testAlphaRectangle.cpp +++ b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp @@ -23,17 +23,18 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void alphaRectangleFunction(Canvas& can) { + Background * bg = can.getBackground(); const int WW = can.getWindowWidth(), WH = can.getWindowHeight(); int a, b, c, d, x, y, w, h; while (can.isOpen()) { can.sleep(); - a = rand() % WW; b = rand() % WH; - c = rand() % WW; d = rand() % WH; - x = (a > c ? c : a); - y = (b > d ? d : b); + a = saferand(-WW/2,WW/2); b = saferand(-WH/2, WH/2); + c = saferand(-WW/2,WW/2); d = saferand(-WH/2, WH/2); + x = (a + c) / 2; + y = (b + d) / 2; w = abs(c - a); h = abs(d - b); - can.drawRectangle(x, y, w, h, ColorInt(rand()%MAX_COLOR, rand()%MAX_COLOR, rand()%MAX_COLOR, 16), true); + bg->drawRectangle(x, y, 0, w, h, 0,0,0, ColorFloat(randfloat(), randfloat(), randfloat(), (float) 16/255)); } } @@ -43,7 +44,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Fancy Rectangles"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Fancy Rectangles", BLACK); c.run(alphaRectangleFunction); } diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp deleted file mode 100644 index 9dbc513a0..000000000 --- a/src/tests/testArrows.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * testArrows.cpp tests displaying the Line class's Arrow and Dotted attributes - */ -#include -using namespace tsgl; - -void arrowFunction(Canvas& c) { - int xs[4] = {250, 250, 750, 750}; - int ys[4] = {250, 750, 250, 750}; - ColorFloat color[2]; - color[0] = BLUE; - color[1] = YELLOW; - - //Draw double headed arrow moving around Canvas - Arrow* doubleArrow = new Arrow(500, 500, 250, 250, WHITE, true); - c.add(doubleArrow); - - for(int i = 0; i < 4; i++) { - - int x = xs[i], y = ys[i]; - - // draw Arrows outlining a square centered at x, y - for(int i = -100; i <= 100; i+= 20) { - c.drawArrow(x, y, x+i, y-100, PURPLE); - c.drawArrow(x, y, x-100, y+i, GREEN); - c.drawArrow(x, y, x+100, y+i, color); - c.drawArrow(x, y, x+i, y+100, RED); - } - } - - int x = 250, y = 250; - int count = 0; - - while( c.isOpen() ) { - if (count == 200) { - c.remove(doubleArrow); - count = 201; - } else if (count == 300) { - c.add(doubleArrow); - count = 301; - } else if (count < 300) { - count++; - } - c.sleep(); - x += 10; if(x > 1000) x = 250; - y += 30; if(y > 1000) y = 250; - doubleArrow->moveHead(x, y); - } - - delete doubleArrow; -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Arrows"); - c.run(arrowFunction); -} \ No newline at end of file diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile new file mode 100644 index 000000000..a998f5a9e --- /dev/null +++ b/src/tests/testArrows/Makefile @@ -0,0 +1,87 @@ +# Makefile for testArrows + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrows + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp new file mode 100644 index 000000000..8414e3fe5 --- /dev/null +++ b/src/tests/testArrows/testArrows.cpp @@ -0,0 +1,76 @@ +/** + * testArrows.cpp tests displaying the Arrow class. + */ +#include +using namespace tsgl; + +void arrowFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.5), ColorFloat(0,1,0,1) }; + Arrow* doubleArrow = new Arrow(100, 100, 50, 200, 5,0,0,0, colors, true); + Arrow* arrow2 = new Arrow(0 ,0 ,0 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), false); + c.add(doubleArrow); + // doubleArrow->setLength(200); + // doubleArrow->changeLength(0); + c.add(arrow2); + + Line * line1 = new Line(100,200,50,300,0,0,0,PURPLE); + c.add(line1); + Line * line = new Line(100,150,50,100,0,0,0,ORANGE); + c.add(line); + Line * line2 = new Line(-250, 150, 75, -200, -50, -75, 0,0,0, PURPLE); + c.add(line2); + + Arrow * a3 = new Arrow(-250, 250, 150, -150, -150, -150, 10, 0,0,0, colors, true); + c.add(a3); + a3->setLength(a3->getLength() / 2); + // doubleArrow->setCenterX(100); + // doubleArrow->setRotationPoint(0,0,0); + // doubleArrow->setYaw(45); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(colors); + // printf("%f\n", doubleArrow->getAlpha()); + + c.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&c, &a3] () { + a3->setSecondEndpoint(c.getMouseX(), c.getMouseY(), 0); + a3->setWidth(saferand(1, 45)); + }); + + GLfloat delta = 5; + bool boolean = true; + while( c.isOpen() ) { + c.sleep(); + // doubleArrow->setCenterX(sin((float)c.getFrameNumber()/90)); + // doubleArrow->setCenterY(sin((float)c.getFrameNumber()/90)); + // doubleArrow->setCenterZ(sin((float)c.getFrameNumber()/90)); + // doubleArrow->setYaw(c.getFrameNumber()); + // doubleArrow->setPitch(c.getFrameNumber()); + // doubleArrow->setRoll(c.getFrameNumber()); + // printf("1: %f, %f, %f\n", doubleArrow->getFirstEndpointX(),doubleArrow->getFirstEndpointY(),doubleArrow->getFirstEndpointZ()); + // printf("2: %f, %f, %f\n", doubleArrow->getSecondEndpointX(),doubleArrow->getSecondEndpointY(),doubleArrow->getSecondEndpointZ()); + // doubleArrow->setLength(sin((float)c.getFrameNumber()/90) * 100 + 200); + // if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { + // delta *= -1; + // arrow2->setIsOutlined(boolean); + // arrow2->setIsFilled(!boolean); + // boolean = !boolean; + // } + // doubleArrow->changeLengthBy(delta); + // a3->setLength(sin((float)c.getFrameNumber()/45) * 100 + 150); + } + + delete doubleArrow; + delete line1; + delete line; + delete line2; + delete arrow2; + delete a3; +} + +int main(int argc, char* argv[]) { + int w = 600; + int h = 600; + Canvas c(-1, -1, w, h, "Arrows", BLACK); + c.run(arrowFunction); +} \ No newline at end of file diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile new file mode 100644 index 000000000..e210b8247 --- /dev/null +++ b/src/tests/testAura/Makefile @@ -0,0 +1,87 @@ +# Makefile for testAura + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAura + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAura.cpp b/src/tests/testAura/testAura.cpp similarity index 89% rename from src/tests/testAura.cpp rename to src/tests/testAura/testAura.cpp index 7b97bcbae..77e9c5cfa 100644 --- a/src/tests/testAura.cpp +++ b/src/tests/testAura/testAura.cpp @@ -21,6 +21,7 @@ inline void scatter(float& f, float max) { * */ void auraFunction(Canvas& can, int segs) { + Background * bg = can.getBackground(); const float SR2 = sqrt(2); const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); const int ccw = CW/2, cch = CH/2; @@ -58,11 +59,11 @@ void auraFunction(Canvas& can, int segs) { if (cf[i].H > 6.0f) cf[i].H = 0.0f; float sang = sin(ang), cang = cos(ang); if (fabs(cang) > fabs(sang)) { - x1[i] = (cang > 0) ? CW : 0; - y1[i] = cch+cch*sang*SR2; + x1[i] = (cang > 0) ? ccw : -ccw; + y1[i] = cch*sang*SR2; } else { - y1[i] = (sang > 0) ? CH : 0; - x1[i] = ccw+ccw*cang*SR2; + y1[i] = (sang > 0) ? cch : -cch; + x1[i] = ccw*cang*SR2; } ang += OFF; } @@ -88,7 +89,7 @@ void auraFunction(Canvas& can, int segs) { } } if (next >= 0) { - can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); + bg->drawTriangle(mx,my,0,x1[next],y1[next],0,x2[next],y2[next],0,0,0,0,cf[next],false); drawn[next] = true; } } @@ -106,7 +107,6 @@ int main(int argc, char* argv[]) { int w = (argc > 1) ? atoi(argv[1]) : -1; int h = (argc > 2) ? atoi(argv[2]) : w; int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs()*2; - Canvas c(-1, -1, w, h, "Aura"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Aura", BLACK); c.run(auraFunction,t); } diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile new file mode 100644 index 000000000..de06d52e5 --- /dev/null +++ b/src/tests/testBackground/Makefile @@ -0,0 +1,87 @@ +# Makefile for testBackground + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBackground + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBackground/testBackground.cpp b/src/tests/testBackground/testBackground.cpp new file mode 100644 index 000000000..58d1362bf --- /dev/null +++ b/src/tests/testBackground/testBackground.cpp @@ -0,0 +1,70 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include +#include + +using namespace tsgl; + +void backgroundFunction(Canvas& can) { + Background * bg = can.getBackground(); + Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); + float x = 0; + + can.bindToButton(TSGL_LEFT, TSGL_PRESS, [&cube]() { + cube->changeXBy(-10); + }); + + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeXBy(10); + }); + + can.bindToButton(TSGL_UP, TSGL_PRESS, [&cube]() { + cube->changeYBy(10); + }); + + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&cube]() { + cube->changeYBy(-10); + }); + + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&cube]() { + cube->changeZBy(-50); + }); + + can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeZBy(50); + }); + + // bg->drawSquare(0,0,0,200,0,0,0,RED); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&bg, &can]() { + bg->setClearColor(Colors::randomColor()); + // can.setBackgroundColor(Colors::randomColor()); + bg->clear(); + // can.clearBackground(); + // printf("%f, %f, %f, %f\n", can.getBackgroundColor().R, can.getBackgroundColor().G, can.getBackgroundColor().B, can.getBackgroundColor().A); + // printf("%f, %f, %f, %f\n", bg->getClearColor().R, bg->getClearColor().G, bg->getClearColor().B, bg->getClearColor().A); + }); + + can.add(cube); + while (can.isOpen()) { + can.sleep(); + // bg->clear(); + x = 200 * sin( (float) can.getFrameNumber()/90); + bg->drawSquare(x,0,0,200,0,0,0,RED, true); + // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); + } + delete cube; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Background", BLUE); + c.run(backgroundFunction); +} \ No newline at end of file diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile new file mode 100644 index 000000000..ba8cab778 --- /dev/null +++ b/src/tests/testBlurImage/Makefile @@ -0,0 +1,87 @@ +# Makefile for testBlurImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBlurImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBlurImage.cpp b/src/tests/testBlurImage/testBlurImage.cpp similarity index 60% rename from src/tests/testBlurImage.cpp rename to src/tests/testBlurImage/testBlurImage.cpp index 005d6399d..95d018d6e 100644 --- a/src/tests/testBlurImage.cpp +++ b/src/tests/testBlurImage/testBlurImage.cpp @@ -16,47 +16,51 @@ int depthtest(int xmin, int ymin, int xmax, int ymax) { return ((xd > yd) ? xd : yd); } -bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { +bool blur(Background * bg, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { if (xmin > xmax || ymin > ymax) return false; if (depth > 0) { int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; - blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); - blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); - blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); - blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); + blur(bg,xmin, ymin, xmid,ymid,numdrawn, depth-1); + blur(bg,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); + blur(bg,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); + blur(bg,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); return false; } - ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); - ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); + ColorFloat top = Colors::blend(bg->getPixel(xmin,ymin),bg->getPixel(xmax,ymin)); + ColorFloat bot = Colors::blend(bg->getPixel(xmin,ymax),bg->getPixel(xmax,ymax)); for (int j = ymin; j <= ymax; ++j) for (int i = xmin; i <= xmax; ++i) - can.drawPoint(i,j,Colors::blend(top,bot)); + bg->drawPixel(i,j,Colors::blend(top,bot)); return true; } void blurImageFunction(Canvas& can, std::string fpath, int threads) { + Background * bg = can.getBackground(); int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + bg->drawImage(0,0,0,fpath,cww,cwh,0,0,0,1.0); int side = sqrt(threads); //Square root of the number of threads, rounded down - can.drawImage(fpath, 0, 0, cww, cwh); can.sleepFor(0.5f); #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square { side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads int tid = omp_get_thread_num(); int ndrawn = 0, xblock = cww/side, yblock = cwh/side; - int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; + int xmin = (tid%side)*xblock - cww/2, ymin = (tid/side)*yblock - cwh/2; int xmax = xmin+xblock; clamp(xmax,0,cww-1); int ymax = ymin+yblock; clamp(ymax,0,cwh-1); int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); - for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); + for (bool d = false; !d && can.isOpen(); d = blur(bg, xmin, ymin, xmax, ymax, ndrawn, depth--)); } } int main(int argc, char* argv[]) { int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; - TextureHandler::getDimensions(fname,w,h); + std::string fname = (argc > 2) ? argv[2] : "./assets/pics/HDR_landscape.jpg"; + Image::getFileResolution(fname,w,h); + w*=0.6; + h*=0.6; + printf("%d, %d\n", w, h); Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); c.run(blurImageFunction,fname,t); } diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile new file mode 100644 index 000000000..434b602b3 --- /dev/null +++ b/src/tests/testCalcPi/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCalcPi + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCalcPi + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCalcPi.cpp b/src/tests/testCalcPi/testCalcPi.cpp similarity index 94% rename from src/tests/testCalcPi.cpp rename to src/tests/testCalcPi/testCalcPi.cpp index 6a3a6074c..f609bd355 100644 --- a/src/tests/testCalcPi.cpp +++ b/src/tests/testCalcPi/testCalcPi.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) { //Setup omp_set_num_threads(numThreads); - IntegralViewer i1(&unitCircleFunction, 800, 800, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); + IntegralViewer i1(&unitCircleFunction, 600, 600, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); //Go! printf("Reference pi: 3.141592653589793238462643383279...)\n"); @@ -70,7 +70,7 @@ int main(int argc, char** argv) { printf("Trapezoids pi: %32.30Lf in %f secs\n", trapezoidsPi, i1.getTrapTime() ); //Bonus! - IntegralViewer i2(&sineFunction, 1200, 800, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); + IntegralViewer i2(&sineFunction, 900, 600, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); i2.rectangleEvaluate(numIntervals); i2.trapezoidEvaluate(numIntervals); } diff --git a/src/tests/testCamera/Makefile b/src/tests/testCamera/Makefile new file mode 100644 index 000000000..c5527f15f --- /dev/null +++ b/src/tests/testCamera/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCamera + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCamera + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCamera/testCamera.cpp b/src/tests/testCamera/testCamera.cpp new file mode 100644 index 000000000..1109c5520 --- /dev/null +++ b/src/tests/testCamera/testCamera.cpp @@ -0,0 +1,157 @@ +/* + * testCamera.cpp + * + * Usage: ./testCamera + */ + +#include +#include + +using namespace tsgl; + +void cameraFunction(Canvas& can) { + Background * bg = can.getBackground(); + Camera * camera = can.getCamera(); + + bg->drawSquare(0, 0, 0, can.getWindowHeight(), 0,0,0, RED); + + ColorFloat colors[8] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1), + ColorFloat(0,0,1,1), ColorFloat(1,1,0,1), + ColorFloat(1,0,1,1), ColorFloat(0,1,1,1), + ColorFloat(0.25,1,0.25,1), ColorFloat(0.25,0.25,1,1)}; + Cube * cube = new Cube(0,0,0,200,0,0,0,colors); + can.add(cube); + + Square * square = new Square(250,250,-250,100,0,0,0,BLUE); + can.add(square); + + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&camera]() { + camera->moveRight(25); + }); + can.bindToButton(TSGL_LEFT, TSGL_PRESS, [&camera]() { + camera->moveLeft(25); + }); + can.bindToButton(TSGL_UP, TSGL_PRESS, [&camera]() { + camera->moveUp(25); + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&camera]() { + camera->moveDown(25); + }); + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&camera]() { + camera->moveForward(25); + }); + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&camera]() { + camera->moveBackward(25); + }); + + can.bindToButton(TSGL_W, TSGL_PRESS, [&camera]() { + camera->changePitchBy(5); + }); + can.bindToButton(TSGL_S, TSGL_PRESS, [&camera]() { + camera->changePitchBy(-5); + }); + can.bindToButton(TSGL_A, TSGL_PRESS, [&camera]() { + camera->changeYawBy(-5); + }); + can.bindToButton(TSGL_D, TSGL_PRESS, [&camera]() { + camera->changeYawBy(5); + }); + + can.bindToButton(TSGL_V, TSGL_PRESS, [&camera]() { + printf("%f\n", camera->getYaw()); + }); + + can.bindToButton(TSGL_B, TSGL_PRESS, [&camera]() { + printf("%f\n", camera->getPitch()); + }); + + /* making sure lookAt() works properly from all angles */ + // float d = camera->getPositionZ(); + // camera->setPositionY(d/2); + // camera->lookAt(0,0,0); + + // can.bindToButton(TSGL_1, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(0); + // camera->setPositionZ(d); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_2, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(-d/3); + // camera->setPositionZ(2*d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_3, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(-2*d/3); + // camera->setPositionZ(d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_4, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(-d); + // camera->setPositionZ(0); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_5, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(-2*d/3); + // camera->setPositionZ(-d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_6, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(-d/3); + // camera->setPositionZ(-2*d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_7, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(0); + // camera->setPositionZ(-d); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_8, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(d/3); + // camera->setPositionZ(-2*d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_9, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(2*d/3); + // camera->setPositionZ(-d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_0, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(d); + // camera->setPositionZ(0); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_R, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(2*d/3); + // camera->setPositionZ(d/3); + // camera->lookAt(0,0,0); + // }); + + // can.bindToButton(TSGL_T, TSGL_PRESS, [&camera, &d]() { + // camera->setPositionX(d/3); + // camera->setPositionZ(2*d/3); + // camera->lookAt(0,0,0); + // }); + + while (can.isOpen()) { + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Moving Camera", BLACK); + c.run(cameraFunction); +} \ No newline at end of file diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile new file mode 100644 index 000000000..061f38504 --- /dev/null +++ b/src/tests/testCircle/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCircle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCircle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCircle/testCircle.cpp b/src/tests/testCircle/testCircle.cpp new file mode 100644 index 000000000..e1740776d --- /dev/null +++ b/src/tests/testCircle/testCircle.cpp @@ -0,0 +1,67 @@ +/* + * testCircle.cpp + * + * Usage: ./testCircle + */ + +#include +#include + +using namespace tsgl; + +void circleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Circle * circle = new Circle(0,0,0,100,0,0,0,colors); + + // printf("%f\n", circle->getAlpha()); + // circle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", circle->getAlpha()); + // circle->setColor(colors); + // printf("%f\n", circle->getAlpha()); + // circle->setCenterX(200); + // circle->setRotationPoint(0,0,0); + can.add(circle); + float floatVal = 0.0f; + GLfloat delta = 1; + while (can.isOpen()) { + can.sleep(); + // circle->setCenterX(sin(floatVal/90) * 100); + // circle->setCenterY(sin(floatVal/90) * 100); + // circle->setCenterZ(sin(floatVal/90) * 100); + // circle->setYaw(floatVal); + // circle->setPitch(floatVal); + // circle->setRoll(floatVal); + // circle->setRadius(sin(floatVal/90) * 100 + 100); + if (circle->getRadius() > 300 || circle->getRadius() < 100) { + delta *= -1; + } + circle->changeRadiusBy(delta); + if (delta > 0) { + circle->setColor(colors); + } else { + circle->setColor(RED); + } + floatVal += 1; + } + + delete circle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Basic Circle", BLACK); + c.run(circleFunction); +} \ No newline at end of file diff --git a/src/tests/testColorPoints.cpp b/src/tests/testColorPoints.cpp deleted file mode 100644 index 668445bc9..000000000 --- a/src/tests/testColorPoints.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * testColorPoints.cpp - * - * Usage: ./testColorPoints - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a neat pattern of points to a Canvas using OMP and takes in a command line - * argument for the number of threads to use. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. - * - The actual number of threads created is stored in: \b nthreads . - * - The number of lines per thread is calculated and stored in: \b myPart . - * - The starting position of each given thread is calculated and stored in: \b myStart . - * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. - * - The color for a thread is calculated. - * - If the point's coordinate is even: - * - Draw a point on the Canvas in the thread's color. - * - Else: - * - Draw the point normally. - * . - * - The function breaks from the outer for loop if the Canvas is closed. - * . - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Number of threads to use. - */ -void colorPointsFunction(Canvas& can, int numberOfThreads) { - Rectangle *rec = new Rectangle(1,1,1,1,BLUE); - can.add(rec); - #pragma omp parallel num_threads(numberOfThreads) - { - int nthreads = omp_get_num_threads(); //Actual number of threads to use - int myPart = can.getWindowHeight() / nthreads + 1; - int myStart = myPart * omp_get_thread_num(); - for (int i = myStart; i < myStart + myPart; i++) { - for (int j = 0; j < can.getWindowWidth(); j++) { - // int id = omp_get_thread_num(); - if (i % 2 == 0) { - can.drawPoint(i, j, BLACK); - } else { - can.drawPoint(i, j, ColorInt(i % 255, j % 255, (i*j) % 255)); - } - } - if (!can.isOpen()) break; - } - } - can.remove(rec); - delete rec; -} - -//Takes in command line arguments for the window width and height as well -//as for the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Dithered Points"); - c.run(colorPointsFunction,t); -} diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile new file mode 100644 index 000000000..fdc954773 --- /dev/null +++ b/src/tests/testColorWheel/Makefile @@ -0,0 +1,87 @@ +# Makefile for testColorWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testColorWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testColorWheel.cpp b/src/tests/testColorWheel/testColorWheel.cpp similarity index 90% rename from src/tests/testColorWheel.cpp rename to src/tests/testColorWheel/testColorWheel.cpp index 3a7404d33..2ec404255 100644 --- a/src/tests/testColorWheel.cpp +++ b/src/tests/testColorWheel/testColorWheel.cpp @@ -39,6 +39,7 @@ using namespace tsgl; * \param threads Number of threads to use. */ void colorWheelFunction(Canvas& can, int threads) { + Background * bg = can.getBackground(); const int CW = can.getWindowWidth() / 2, // Half the window's width CH = can.getWindowHeight() / 2; // Half the window's height const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel @@ -52,12 +53,12 @@ void colorWheelFunction(Canvas& can, int threads) { while (can.isOpen()) { can.sleep(); int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; - x2 = CW + RADIUS * sin(GRADIENT * start); - y2 = CH + RADIUS * cos(GRADIENT * start); - x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); - y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); - can.drawTriangle(CW, CH, x2, y2, x3, y3, - ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); + x2 = RADIUS * sin(GRADIENT * start); + y2 = RADIUS * cos(GRADIENT * start); + x3 = RADIUS * sin(GRADIENT * (start + 1)); + y3 = RADIUS * cos(GRADIENT * (start + 1)); + bg->drawTriangle(0,0,0, x2,y2,0, x3,y3,0, 0,0,0, + ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), false); } } } diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp deleted file mode 100644 index 56c61c714..000000000 --- a/src/tests/testConcavePolygon.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void concavePolygonFunction(Canvas& can) { - const int PSIZE = 64; - - int x[PSIZE], xx[PSIZE]; - int y[PSIZE], yy[PSIZE]; - ColorFloat color[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) - color[i] = Colors::randomColor(1.0f); - - x[0] = 100; y[0] = 100; - x[1] = 200; y[1] = 100; - x[2] = 200; y[2] = 200; - x[3] = 300; y[3] = 200; - x[4] = 300; y[4] = 100; - x[5] = 400; y[5] = 100; - x[6] = 400; y[6] = 400; - x[7] = 300; y[7] = 300; - x[8] = 250; y[8] = 400; - x[9] = 200; y[9] = 300; - x[10] = 100; y[10] = 400; - - for (int i = 0; i < PSIZE; ++i) { - if (i % 2 == 0) { - xx[i] = can.getWindowWidth() / 2 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = can.getWindowHeight() / 2 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); - } else { - xx[i] = can.getWindowWidth() / 2 + 300 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = can.getWindowHeight() / 2 - 300 * cos((1.0f*i)/(PSIZE) * PI * 2); - } - } - - ConcavePolygon * c1 = new ConcavePolygon(11, x, y, color, false); - ConcavePolygon * c2 = new ConcavePolygon(PSIZE, xx, yy, color, true); - can.add(c1); can.add(c2); - - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - // note: when you call drawConcavePolygon, you MUST give it the correct size. - // otherwise, it is always wrong and inconsistent in how it is wrong. - can.pauseDrawing(); - c1->setCenter(can.getWindowWidth() / 2 + 450 * sin((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2), can.getWindowHeight() / 2 - 450 * cos((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2) ); - can.resumeDrawing(); - } - - delete c1; - delete c2; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Concave Polygons"); - c.setBackgroundColor(WHITE); - c.run(concavePolygonFunction); -} diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile new file mode 100644 index 000000000..db8cc2b44 --- /dev/null +++ b/src/tests/testConcavePolygon/Makefile @@ -0,0 +1,87 @@ +# Makefile for testConcavePolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConcavePolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConcavePolygon/testConcavePolygon.cpp b/src/tests/testConcavePolygon/testConcavePolygon.cpp new file mode 100644 index 000000000..00cf81104 --- /dev/null +++ b/src/tests/testConcavePolygon/testConcavePolygon.cpp @@ -0,0 +1,91 @@ +/* + * testConcavePolygon.cpp + * + * Usage: ./testConcavePolygon + */ + +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/** + * \brief Draw Concave polygons, which have one or more interior angles > 180 + * \note See http://www.mathopenref.com/polygonconcave.html + * \details + * - Initialize a constant \b PSIZE. + * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. + * - Create an empty array of colors of size \b PSIZE and fill it with random colors. + * - Fill the arrays of integers, \b xx and \b yy, with specific values. + * - While the Canvas is open: + * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. + * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void concavePolygonFunction(Canvas& can) { + const int PSIZE = 64; + + float xx[PSIZE]; + float yy[PSIZE]; + ColorFloat color[PSIZE]; + for (unsigned i = 0; i < PSIZE; ++i) + color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); + + color[1] = color[PSIZE-1]; + + xx[0] = 0; + yy[0] = 0; + for (int i = 0; i < PSIZE-1; ++i) { + if (i % 2 == 0) { + xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } else { + xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } + } + + // for (int i = 0; i < PSIZE; ++i) { + // if (i % 2 == 0) { + // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } else { + // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } + // } + + ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(color); + // printf("%f\n", c2->getAlpha()); + can.add(c2); + + float floatVal = 0.0f; + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + // c2->setCenterX(sin(floatVal/90)); + // c2->setCenterY(sin(floatVal/90)); + // c2->setCenterZ(sin(floatVal/90)); + // c2->setYaw(floatVal); + // c2->setPitch(floatVal); + // c2->setRoll(floatVal); + floatVal += 1; + } + + delete c2; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Concave Polygons", WHITE); + c.run(concavePolygonFunction); +} diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile new file mode 100644 index 000000000..e51e16a5b --- /dev/null +++ b/src/tests/testCone/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCone + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCone + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCone/testCone.cpp b/src/tests/testCone/testCone.cpp new file mode 100644 index 000000000..951d05b18 --- /dev/null +++ b/src/tests/testCone/testCone.cpp @@ -0,0 +1,88 @@ +/* + * testCone.cpp + * + * Usage: ./testCone + */ + +#include +#include + +using namespace tsgl; + +void coneFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; + Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); + Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); + can.add(testCone); + can.add(testCone2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCone->setCenterX(sin(rotation)*2); + // testCone->setCenterY(cos(rotation)*2); + // testCone->setCenterZ(sin(rotation)); + // testCone->setYaw(rotation*45); + // testCone->setPitch(rotation*45); + testCone->setRoll(rotation*45); + // testCone->setHeight(sin(rotation)+1.01); + // testCone->setRadius(sin(rotation)+1.01); + // if(testCone->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCone->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeHeightBy(delta); + // if(testCone->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCone->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCone->setColor(RED); + } else { + testCone->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCone; + delete testCone2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cone", BLACK); + c.run(coneFunction); +} \ No newline at end of file diff --git a/src/tests/testConstructors.cpp b/src/tests/testConstructors.cpp deleted file mode 100644 index ff241b947..000000000 --- a/src/tests/testConstructors.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void constructorFunction(Canvas& can) { - // srand(time(NULL)); - const int PSIZE = 50; - - ColorFloat fillColor[PSIZE]; - ColorFloat outlineColor[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) { - fillColor[i] = Colors::randomColor(1.0f); - outlineColor[i] = Colors::randomColor(1.0f); - } - - can.drawRectangle(15, 5, 70, 95, fillColor[0], true); - can.drawRectangle(115, 5, 70, 95, fillColor[0], false); - can.drawRectangle(215, 5, 70, 95, fillColor, true); - can.drawRectangle(315, 5, 70, 95, fillColor, false); - - can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); - can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); - can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); - can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); - - can.drawSquare(5, 105, 90, fillColor[0], true); - can.drawSquare(105, 105, 90, fillColor[0], false); - can.drawSquare(205, 105, 90, fillColor, true); - can.drawSquare(305, 105, 90, fillColor, false); - - can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); - can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); - can.drawSquare(605, 105, 90, fillColor[0], outlineColor); - can.drawSquare(705, 105, 90, fillColor, outlineColor); - - can.drawStar(50, 250, 45, 6, fillColor[0], true, false); - can.drawStar(150, 250, 45, 6, fillColor[0], false, true); - can.drawStar(250, 250, 45, 6, fillColor, true, false); - can.drawStar(350, 250, 45, 6, fillColor, false, true); - - can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); - can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); - can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); - can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); - - can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); - can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); - can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); - can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); - - can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); - can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); - can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); - can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); - - can.drawEllipse(50, 450, 35, 45, fillColor[0], true); - can.drawEllipse(150, 450, 35, 45, fillColor[0], false); - can.drawEllipse(250, 450, 35, 45, fillColor, true); - can.drawEllipse(350, 450, 35, 45, fillColor, false); - - can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); - can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); - can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); - can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); - - can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); - can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); - can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); - can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); - - can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); - can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); - can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); - can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); - - can.drawCircle(50, 650, 45, fillColor[0], true); - can.drawCircle(150, 650, 45, fillColor[0], false); - can.drawCircle(250, 650, 45, fillColor, true); - can.drawCircle(350, 650, 45, fillColor, false); - - can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); - can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); - can.drawCircle(650, 650, 45, fillColor[0], outlineColor); - can.drawCircle(750, 650, 45, fillColor, outlineColor); - - int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; - - x1[0] = x1[1] = 5; - x1[2] = 50; - x1[3] = x1[4] = 95; - - x2[0] = x2[1] = 105; - x2[2] = 150; - x2[3] = x2[4] = 195; - - x3[0] = x3[1] = 205; - x3[2] = 250; - x3[3] = x3[4] = 295; - - x4[0] = x4[1] = 305; - x4[2] = 350; - x4[3] = x4[4] = 395; - - x5[0] = x5[1] = 405; - x5[2] = 450; - x5[3] = x5[4] = 495; - - x6[0] = x6[1] = 505; - x6[2] = 550; - x6[3] = x6[4] = 595; - - x7[0] = x7[1] = 605; - x7[2] = 650; - x7[3] = x7[4] = 695; - - x8[0] = x8[1] = 705; - x8[2] = 750; - x8[3] = x8[4] = 795; - - y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; - y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; - y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; - y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; - y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; - - can.drawTriangleStrip(5, x1, y1, fillColor[0], true); - can.drawTriangleStrip(5, x2, y2, fillColor[0], false); - can.drawTriangleStrip(5, x3, y3, fillColor, true); - can.drawTriangleStrip(5, x4, y4, fillColor, false); - - can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); - can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); - can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); - can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); - - int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], - y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; - - x9[0] = x9[1] = 5; - x9[2] = x9[5] = 50; - x9[3] = x9[4] = 95; - - x10[0] = x10[1] = 105; - x10[2] = x10[5] = 150; - x10[3] = x10[4] = 195; - - x11[0] = x11[1] = 205; - x11[2] = x11[5] = 250; - x11[3] = x11[4] = 295; - - x12[0] = x12[1] = 305; - x12[2] = x12[5] = 350; - x12[3] = x12[4] = 395; - - x13[0] = x13[1] = 405; - x13[2] = x13[5] = 450; - x13[3] = x13[4] = 495; - - x14[0] = x14[1] = 505; - x14[2] = x14[5] = 550; - x14[3] = x14[4] = 595; - - x15[0] = x15[1] = 605; - x15[2] = x15[5] = 650; - x15[3] = x15[4] = 695; - - x16[0] = x16[1] = 705; - x16[2] = x16[5] = 750; - x16[3] = x16[4] = 795; - - y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; - y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; - y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; - y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; - y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; - y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; - - can.drawConvexPolygon(6, x9, y9, fillColor[0], true); - can.drawConvexPolygon(6, x10, y10, fillColor[0], false); - can.drawConvexPolygon(6, x11, y11, fillColor, true); - can.drawConvexPolygon(6, x12, y12, fillColor, false); - - can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); - can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); - can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); - can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); - - int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], - y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; - - x17[0] = x17[1] = 5; - x17[2] = x17[5] = 50; - x17[3] = x17[4] = 95; - - x18[0] = x18[1] = 105; - x18[2] = x18[5] = 150; - x18[3] = x18[4] = 195; - - x19[0] = x19[1] = 205; - x19[2] = x19[5] = 250; - x19[3] = x19[4] = 295; - - x20[0] = x20[1] = 305; - x20[2] = x20[5] = 350; - x20[3] = x20[4] = 395; - - x21[0] = x21[1] = 405; - x21[2] = x21[5] = 450; - x21[3] = x21[4] = 495; - - x22[0] = x22[1] = 505; - x22[2] = x22[5] = 550; - x22[3] = x22[4] = 595; - - x23[0] = x23[1] = 605; - x23[2] = x23[5] = 650; - x23[3] = x23[4] = 695; - - x24[0] = x24[1] = 705; - x24[2] = x24[5] = 750; - x24[3] = x24[4] = 795; - - y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; - y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; - y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; - y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; - y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; - y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; - - can.drawConcavePolygon(6, x17, y17, fillColor[0], true); - can.drawConcavePolygon(6, x18, y18, fillColor[0], true); - can.drawConcavePolygon(6, x19, y19, fillColor, true); - can.drawConcavePolygon(6, x20, y20, fillColor, true); - - can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); - can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); - can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); - can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); - - can.drawArrow(805, 5, 895, 95, fillColor[3], true); - can.drawArrow(805, 105, 895, 195, fillColor, true); - - can.drawLine(805, 205, 895, 295, fillColor[3]); - can.drawLine(805, 305, 895, 395, fillColor); - - int x25[5], x26[5], y25[5], y26[5]; - - x25[0] = x26[0] = 820; - x25[1] = x26[1] = 805; - x25[2] = x26[2] = 880; - x25[3] = x26[3] = 895; - x25[4] = x26[4] = 870; - - y25[0] = 450; - y25[1] = 405; - y25[2] = 420; - y25[3] = 460; - y25[4] = 495; - - y26[0] = 550; - y26[1] = 505; - y26[2] = 520; - y26[3] = 560; - y26[4] = 595; - - can.drawPolyline(5, x25, y25, fillColor[3]); - can.drawPolyline(5, x26, y26, outlineColor); - - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - - } -} - -int main(int argc, char* argv[]) { - int w = 0.9*Canvas::getDisplayHeight(); - int h = w; - Canvas c(-1, -1, w, h, "Constructors"); - c.setBackgroundColor(WHITE); - c.run(constructorFunction); -} diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile new file mode 100644 index 000000000..87077fa86 --- /dev/null +++ b/src/tests/testConvexPolygon/Makefile @@ -0,0 +1,87 @@ +# Makefile for testConvexPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConvexPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConvexPolygon/testConvexPolygon.cpp b/src/tests/testConvexPolygon/testConvexPolygon.cpp new file mode 100644 index 000000000..43174f924 --- /dev/null +++ b/src/tests/testConvexPolygon/testConvexPolygon.cpp @@ -0,0 +1,57 @@ +/* + * testConvexPolygon.cpp + * + * Usage: ./testConvexPolygon + */ + +#include +#include + +using namespace tsgl; + +void convexPolygonFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { -50,-50, 0,25,50, 50, 25 }; + float y[] = { -50, 25,50,40,10,-10,-50 }; + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); + // cp->setCenterX(2); + // cp->setRotationPoint(0,0,0); + can.add(cp); + float floatVal = 0.0f; + while (can.isOpen()) { + can.sleep(); + // cp->setCenterX(sin(floatVal/90) * 100); + // cp->setCenterY(sin(floatVal/90) * 100); + // cp->setCenterZ(sin(floatVal/90) * 100); + // cp->setYaw(floatVal); + // cp->setPitch(floatVal); + // cp->setRoll(floatVal); + // if (floatVal < 200) { + // cp->setColor(colors); + // } else { + // cp->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete cp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon", BLACK); + c.run(convexPolygonFunction); +} \ No newline at end of file diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile new file mode 100644 index 000000000..ed8e95fb4 --- /dev/null +++ b/src/tests/testCosineIntegral/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCosineIntegral + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCosineIntegral + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCosineIntegral.cpp b/src/tests/testCosineIntegral/testCosineIntegral.cpp similarity index 72% rename from src/tests/testCosineIntegral.cpp rename to src/tests/testCosineIntegral/testCosineIntegral.cpp index c2dd5b3fe..c4c834791 100644 --- a/src/tests/testCosineIntegral.cpp +++ b/src/tests/testCosineIntegral/testCosineIntegral.cpp @@ -40,22 +40,34 @@ using namespace tsgl; * \param numberOfThreads Reference to the number of threads to use. */ void cosineIntegralFunction(Cart& can, int numberOfThreads) { + CartesianBackground * bg = can.getBackground(); int threads = numberOfThreads; if (threads <= 0) { threads = 1; } - can.drawAxes(0, 0, PI/4, .5); + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&can, &bg] () { + // float mouseX, mouseY; + // ColorFloat c; + // mouseX = can.getMouseX(); + // mouseY = can.getMouseY(); + // printf("%f, %f\n", mouseX, mouseY); + // bg->drawPixel(mouseX, mouseY, ColorInt(255,0,0,255)); + // // c = bg->getPixel(mouseX, mouseY); + // // printf("%f, %f, %f, %f\n", c.R, c.G, c.B, c.A); + // }); + + bg->drawAxes(0, 0, PI/4, .5); long double pw = can.getPixelWidth(); CosineFunction function1; - can.drawFunction(function1); + bg->drawFunction(function1, 0.1f); //\u03C0 = π - can.setFont("../assets/freefont/FreeSerif.ttf"); - can.drawText(L"-1.5\u03C0", -1.5 * PI - .1, .25, 20); // Note the important capital L, used to support Unicode. - can.drawText(L"1.5\u03C0", 1.5 * PI - .2, .25, 20); - can.drawText(L"1", .1, 1.05, 20); - can.drawText(L"-1", .1, -1.1, 20); + std::string font = "./assets/freefont/FreeSerif.ttf"; + bg->drawText( 1.5 * PI - .2, .4, 0, L"1.5\u03C0", font, 0.15, 0,0,0, BLACK); + bg->drawText(-1.4 * PI - .1, .4, 0, L"-1.5\u03C0", font, 0.15, 0,0,0, BLACK); // Note the important capital L, used to support Unicode. + bg->drawText(.15, 1.1, 0, L"1", font, 0.15, 0,0,0, BLACK); + bg->drawText(.18, -1, 0, L"-1", font, 0.15, 0,0,0, BLACK); #pragma omp parallel num_threads(threads) { @@ -66,9 +78,13 @@ void cosineIntegralFunction(Cart& can, int numberOfThreads) { for (long double i = start; i < stop; i += pw) { if (!can.isOpen()) break; can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - can.drawLine(i, 0, i, function1.valueAt(i), Colors::highContrastColor(omp_get_thread_num())); + bg->drawLine(i, 0, 0, i, function1.valueAt(i), 0, 0,0,0, Colors::highContrastColor(omp_get_thread_num())); } } + + while (can.isOpen()) { + can.sleep(); + } } //Takes in command line arguments for the width and height of the window @@ -79,7 +95,7 @@ int main(int argc, char* argv[]) { if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads to use - Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", FRAME / 2); - c.setBackgroundColor(WHITE); + Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", WHITE, FRAME / 2); + // c.zoom(0,1,0.036); c.run(cosineIntegralFunction,t); } diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile new file mode 100644 index 000000000..7d4cf0e26 --- /dev/null +++ b/src/tests/testCube/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCube + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCube + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCube/testCube.cpp b/src/tests/testCube/testCube.cpp new file mode 100644 index 000000000..30b640e4b --- /dev/null +++ b/src/tests/testCube/testCube.cpp @@ -0,0 +1,80 @@ +/* + * testCube.cpp + * + * Usage: ./testCube + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); + Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); + can.add(testCube); + + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(colors); + // printf("%f\n", testCube2->getAlpha()); + can.add(testCube2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { + testCube->setIsOutlined(boolean); + boolean = !boolean; + }); + + bool ss = false; + while (can.isOpen()) { + can.sleep(); + // testCube->setCenterX(sin(rotation)*200); + // testCube->setCenterY(cos(rotation)*200); + // testCube->setCenterZ(sin(rotation)*100); + // testCube->setYaw(rotation*45); + testCube->setPitch(rotation*45); + // testCube->setRoll(rotation*45); + // testCube->setSideLength(cos(rotation) * 100 +101); + // if(testCube->getSideLength() >= 2) { + // delta = -5; + // } + // if(testCube->getSideLength() <= 5) { + // delta = 5; + // } + // testCube->changeSideLengthBy(delta); + //testCube2->setRoll(rotation); + // if (rotation*45 >= 360) { + // if (boolean) { + // testCube->setColor(RED); + // } else { + // testCube->setColor(colors); + // } + // boolean = !boolean; + // rotation = 0; + // } + if (can.getFrameNumber() > 50 && !ss) { + can.takeScreenShot(); + ss = true; + } + rotation+=0.01; + } + + delete testCube; + delete testCube2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cube", BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile new file mode 100644 index 000000000..d17396f16 --- /dev/null +++ b/src/tests/testCuboid/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCuboid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCuboid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCuboid/testCuboid.cpp b/src/tests/testCuboid/testCuboid.cpp new file mode 100644 index 000000000..ac407e5e9 --- /dev/null +++ b/src/tests/testCuboid/testCuboid.cpp @@ -0,0 +1,85 @@ +/* + * testCuboid.cpp + * + * Usage: ./testCuboid + */ + +#include +#include + +using namespace tsgl; + +void cuboidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); + Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(colors); + // printf("%f\n", testCuboid2->getAlpha()); + can.add(testCuboid); + can.add(testCuboid2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false;; + while (can.isOpen()) { + can.sleep(); + // testCuboid->setCenterX(sin(rotation)*200); + // testCuboid->setCenterY(cos(rotation)*200); + // testCuboid->setCenterZ(sin(rotation)*100); + // testCuboid->setYaw(rotation*45); + testCuboid->setPitch(rotation*45); + // testCuboid->setRoll(rotation*45); + // testCuboid->setWidth(cos(rotation)*100+101); + // testCuboid->setHeight(cos(rotation)*100+301); + // testCuboid->setLength(cos(rotation)*100+201); + // if(testCuboid->getWidth() >= 200) { + // delta = -5; + // } + // if(testCuboid->getWidth() <= 5) { + // delta = 5; + // } + // testCuboid->changeWidthBy(delta); + + // if(testCuboid->getHeight() >= 500) { + // delta = -5; + // } + // if(testCuboid->getHeight() <= 300) { + // delta = 5; + // } + // testCuboid->changeHeightBy(delta); + + // if(testCuboid->getLength() >= 300) { + // delta = -5; + // } + // if(testCuboid->getLength() <= 100) { + // delta = 5; + // } + // testCuboid->changeLengthBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCuboid->setColor(RED); + } else { + testCuboid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCuboid; + delete testCuboid2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cuboid", BLACK); + c.run(cuboidFunction); +} \ No newline at end of file diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile new file mode 100644 index 000000000..eecdbd29a --- /dev/null +++ b/src/tests/testCylinder/Makefile @@ -0,0 +1,87 @@ +# Makefile for testCylinder + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCylinder + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCylinder/testCylinder.cpp b/src/tests/testCylinder/testCylinder.cpp new file mode 100644 index 000000000..8df38a692 --- /dev/null +++ b/src/tests/testCylinder/testCylinder.cpp @@ -0,0 +1,75 @@ +/* + * testCylinder.cpp + * + * Usage: ./testCylinder + */ + +#include +#include + +using namespace tsgl; + +void cylinderFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); + can.add(testCylinder); + can.add(testCylinder2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCylinder->setCenterX(sin(rotation)*2); + // testCylinder->setCenterY(cos(rotation)*2); + // testCylinder->setCenterZ(sin(rotation)); + // testCylinder->setYaw(rotation*45); + testCylinder->setPitch(rotation*45); + // testCylinder->setRoll(rotation*45); + // testCylinder->setHeight(sin(rotation)+1.01); + // testCylinder->setRadius(sin(rotation)+1.01); + // if(testCylinder->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeHeightBy(delta); + // if(testCylinder->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testCylinder->setColor(RED); + } else { + testCylinder->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCylinder; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); + c.run(cylinderFunction); +} \ No newline at end of file diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile new file mode 100644 index 000000000..86a1ae090 --- /dev/null +++ b/src/tests/testDice/Makefile @@ -0,0 +1,87 @@ +# Makefile for testDice + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDice + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDice/testDice.cpp b/src/tests/testDice/testDice.cpp new file mode 100644 index 000000000..5d674296b --- /dev/null +++ b/src/tests/testDice/testDice.cpp @@ -0,0 +1,179 @@ +/* + * testDice.cpp + * + * Usage: ./testDice + * Note: currently has some interesting rotation issues that mean that the + * API will probably have to be updated. Not compiling since it won't + * really work, alter the Makefile to understand the issue. Has to do with composite + * Euler angles. + */ + +#include +#include + +using namespace tsgl; + +void diceFunction(Canvas& can) { + Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); + can.add(die); + + RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); + can.add(spot1); + spot1->setRotationPoint(0,0,0); + + + RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_1->setRotationPoint(0,0,0); + can.add(spot2_1); + RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_2->setRotationPoint(0,0,0); + can.add(spot2_2); + + RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); + spot3_1->setRotationPoint(0,0,0); + can.add(spot3_1); + RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); + spot3_2->setRotationPoint(0,0,0); + can.add(spot3_2); + RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); + spot3_3->setRotationPoint(0,0,0); + can.add(spot3_3); + + // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_1->setRotationPoint(0,0,0); + // can.add(spot4_1); + // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_2->setRotationPoint(0,0,0); + // can.add(spot4_2); + // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_3->setRotationPoint(0,0,0); + // can.add(spot4_3); + // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_4->setRotationPoint(0,0,0); + // can.add(spot4_4); + + RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); + spot5_1->setRotationPoint(0,0,0); + can.add(spot5_1); + RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_2->setRotationPoint(0,0,0); + can.add(spot5_2); + RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_3->setRotationPoint(0,0,0); + can.add(spot5_3); + RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_4->setRotationPoint(0,0,0); + can.add(spot5_4); + RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_5->setRotationPoint(0,0,0); + can.add(spot5_5); + + RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_1); + RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_2); + RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_3); + RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_4); + RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_5); + RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_6); + spot6_1->setRotationPoint(0,0,0); + spot6_2->setRotationPoint(0,0,0); + spot6_3->setRotationPoint(0,0,0); + spot6_4->setRotationPoint(0,0,0); + spot6_5->setRotationPoint(0,0,0); + spot6_6->setRotationPoint(0,0,0); + + // die->setRoll(45); + // spot1->setRoll(45); + // spot2_1->setRoll(45-90); + // spot2_2->setRoll(45-90); + // spot3_1->setRoll(180); + // spot3_2->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot4_1->setRoll(45); + // spot4_2->setRoll(45); + // spot4_3->setRoll(45); + // spot4_4->setRoll(45); + // spot5_1->setRoll(45+90); + // spot5_2->setRoll(45+90); + // spot5_3->setRoll(45+90); + // spot5_4->setRoll(45+90); + // spot5_5->setRoll(45+90); + // spot6_1->setRoll(45+180); + // spot6_2->setRoll(45+180); + // spot6_3->setRoll(45+180); + // spot6_4->setRoll(45+180); + // spot6_5->setRoll(45+180); + // spot6_6->setRoll(45+180); + + float rotation = 0; + while (can.isOpen()) { + can.sleep(); + // die->setRoll(rotation); + // spot1->setRoll(rotation); + // spot2_1->setRoll(rotation-90); + // spot2_2->setRoll(rotation-90); + // spot3_1->setPitch(rotation); + // spot3_2->setPitch(rotation); + // spot3_3->setPitch(rotation); + // spot4_1->setRoll(rotation); + // spot4_2->setRoll(rotation); + // spot4_3->setRoll(rotation); + // spot4_4->setRoll(rotation); + // spot5_1->setRoll(rotation+90); + // spot5_2->setRoll(rotation+90); + // spot5_3->setRoll(rotation+90); + // spot5_4->setRoll(rotation+90); + // spot5_5->setRoll(rotation+90); + // spot6_1->setRoll(rotation+180); + // spot6_2->setRoll(rotation+180); + // spot6_3->setRoll(rotation+180); + // spot6_4->setRoll(rotation+180); + // spot6_5->setRoll(rotation+180); + // spot6_6->setRoll(rotation+180); + + die->setPitch(rotation); + spot1->setPitch(rotation); + spot2_1->setPitch(rotation); + spot2_2->setPitch(rotation); + spot3_1->setPitch(rotation-90); + spot3_2->setPitch(rotation-90); + spot3_3->setPitch(rotation-90); + // spot4_1->setPitch(rotation+90); + // spot4_2->setPitch(rotation+90); + // spot4_3->setPitch(rotation+90); + // spot4_4->setPitch(rotation+90); + spot5_1->setPitch(rotation); + spot5_2->setPitch(rotation); + spot5_3->setPitch(rotation); + spot5_4->setPitch(rotation); + spot5_5->setPitch(rotation); + spot6_1->setPitch(rotation); + spot6_2->setPitch(rotation); + spot6_3->setPitch(rotation); + spot6_4->setPitch(rotation); + spot6_5->setPitch(rotation); + spot6_6->setPitch(rotation); + rotation += 1; + } + + delete die; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Dice Rolling"); + c.run(diceFunction); +} \ No newline at end of file diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile new file mode 100644 index 000000000..6af0a30eb --- /dev/null +++ b/src/tests/testDiorama/Makefile @@ -0,0 +1,87 @@ +# Makefile for testDiorama + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDiorama + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDiorama/testDiorama.cpp b/src/tests/testDiorama/testDiorama.cpp new file mode 100644 index 000000000..82214f2f6 --- /dev/null +++ b/src/tests/testDiorama/testDiorama.cpp @@ -0,0 +1,118 @@ +/* + * testDiorama.cpp + * + * Usage: ./testDiorama + */ + +#include +#include + +using namespace tsgl; + +void dioramaFunction(Canvas& can) { + Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); + // can.add(blankCanvas); + + Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaLeft); + Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaRight); + Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaTop); + Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaBottom); + + Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunk); + + Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); + // can.add(leaves); + + Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunkFlat); + + Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); + // can.add(leavesFlat); + + float counter = 0; + while (can.isOpen()) { + // can.sleepFor(0.5); + can.sleep(); + if (can.getFrameNumber() > 700 && counter < 1) { + can.add(blankCanvas); + counter++; + } + if(can.getFrameNumber() > 1700 && counter < 2) { + can.add(trunkFlat); + counter++; + } + if(can.getFrameNumber() > 1800 && counter < 3) { + can.add(leavesFlat); + counter++; + } + if(can.getFrameNumber() > 2300 && counter < 4) { + can.add(emptyDioramaLeft); + can.add(emptyDioramaRight); + can.add(emptyDioramaTop); + can.add(emptyDioramaBottom); + counter++; + } + if(can.getFrameNumber() > 3500 && counter < 5) { + can.add(trunk); + counter++; + } + if(can.getFrameNumber() > 3600 && counter < 6) { + can.add(leaves); + counter++; + } + if(can.getFrameNumber() > 4000 && counter < 7) { + if(emptyDioramaLeft->getWidth() > 15) { + emptyDioramaLeft->changeWidthBy(-270/20); + emptyDioramaRight->changeWidthBy(-270/20); + emptyDioramaTop->changeHeightBy(-270/20); + emptyDioramaBottom->changeHeightBy(-270/20); + emptyDioramaTop->changeZBy(135/20); + emptyDioramaBottom->changeZBy(135/20); + emptyDioramaLeft->changeZBy(135/20); + emptyDioramaRight->changeZBy(135/20); + trunk->changeLengthBy(-25/20); + trunk->changeZBy(135/20); + leaves->changeZRadiusBy(-40/20); + leaves->changeZBy(135/20); + } else { + emptyDioramaLeft->setWidth(1); + emptyDioramaRight->setWidth(1); + emptyDioramaTop->setHeight(1); + emptyDioramaBottom->setHeight(1); + emptyDioramaTop->setCenterZ(135); + emptyDioramaBottom->setCenterZ(135); + emptyDioramaLeft->setCenterZ(135); + emptyDioramaRight->setCenterZ(135); + trunk->setLength(1); + trunk->setCenterZ(135); + leaves->setZRadius(1); + leaves->setCenterZ(135); + counter++; + } + } + } + + delete blankCanvas; + delete emptyDioramaLeft; + delete emptyDioramaRight; + delete emptyDioramaTop; + delete emptyDioramaBottom; + delete leaves; + delete trunkFlat; + delete leavesFlat; + +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting", WHITE); + c.run(dioramaFunction); +} \ No newline at end of file diff --git a/src/tests/testDumbSort.cpp b/src/tests/testDumbSort.cpp deleted file mode 100644 index f9eba386d..000000000 --- a/src/tests/testDumbSort.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * testDumbSort.cpp - * - * Usage: ./testDumbSort - */ - -#include - -using namespace tsgl; - -/*! - * \brief Provides a visualization for a basic (and slow) shaker sort. - * \details - * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. - * - An integer array of size \b SIZE is allocated. - * - A flag \b goingUp is set. - * - Our integer array is filled with random integers under the Canvas' height. - * - The background color is set to gray for visibility. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - While the Canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - If the minimum sorted element is greater than or equals the maximum, we're done. - * - At a rate of \b IPF times a second: - * - If we're going up and the element above us is less than us, swap. - * - If we're going down and the element below us is less than us, swap. - * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. - * . - * - Pause the animation. - * - Clear the Canvas. - * - From 0 to \b SIZE: - * - Get the height of each element in the integer array. - * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. - * . - * - Resume the animation. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void dumbSortFunction(Canvas& can) { - const int SIZE = 550, // Size of the data pool (set to 550 by default) - IPF = 50; // Iterations per frame - int numbers[SIZE]; // Array to store the data - int pos = 0, temp, min = 1, max = SIZE - 2, lastSwap = 0; - bool goingUp = true; - for (int i = 0; i < SIZE; i++) - numbers[i] = rand() % (can.getWindowHeight() - 40); - can.setBackgroundColor(GRAY); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - if (min >= max) return; // We are done sorting - for (int i = 0; i < IPF; i++) { - if (goingUp) { - if (numbers[pos] > numbers[pos + 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos + 1]; - numbers[pos + 1] = temp; - lastSwap = pos; - } - if (pos >= max) { - pos = max; - max = (lastSwap < max) ? lastSwap : max - 1; - goingUp = !goingUp; - } else - pos++; - } else { - if (numbers[pos] < numbers[pos - 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos - 1]; - numbers[pos - 1] = temp; - lastSwap = pos; - } - if (pos <= min) { - pos = min; - min = (lastSwap > min) ? lastSwap : min + 1; - goingUp = !goingUp; - } else - pos--; - } - } - int start = 50, width = 1, height; - int cwh = can.getWindowHeight() - 20; - ColorFloat color; - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - can.clearProcedural(); - for (int i = 0; i < SIZE; i++, start += width * 2) { - height = numbers[i]; - color = ColorInt(MAX_COLOR, (i == pos) ? MAX_COLOR : 0, 0); - can.drawRectangle(start, cwh - height, width, height, color); - } - can.resumeDrawing(); //Tell the Canvas it can resume drawing - } -} - -//Takes in command line arguments for the window width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid - w = 1200; h = 900; // If not, set the width and height to a default value - } - Canvas c(-1, -1, w, h, "Shaker Sort"); - c.run(dumbSortFunction); -} diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile new file mode 100644 index 000000000..ece8656ce --- /dev/null +++ b/src/tests/testEllipse/Makefile @@ -0,0 +1,87 @@ +# Makefile for testEllipse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipse/testEllipse.cpp b/src/tests/testEllipse/testEllipse.cpp new file mode 100644 index 000000000..dacee93d4 --- /dev/null +++ b/src/tests/testEllipse/testEllipse.cpp @@ -0,0 +1,71 @@ +/* + * testEllipse.cpp + * + * Usage: ./testEllipse + */ + +#include +#include + +using namespace tsgl; + +void ellipseFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); + // ellipse->setCenterX(200); + // ellipse->setRotationPoint(0,0,0); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(colors); + // printf("%f\n", ellipse->getAlpha()); + can.add(ellipse); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // ellipse->setCenterX(sin(floatVal/90) * 100); + // ellipse->setCenterY(sin(floatVal/90) * 100); + // ellipse->setCenterZ(sin(floatVal/90) * 100); + // ellipse->setYaw(floatVal); + // ellipse->setPitch(floatVal); + // ellipse->setRoll(floatVal); + // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); + // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); + // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { + // delta *= -1; + // } + // ellipse->changeXRadiusBy(delta); + if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { + delta *= -1; + } + ellipse->changeYRadiusBy(delta); + if (delta > 0) { + ellipse->setColor(colors); + } else { + ellipse->setColor(RED); + } + floatVal += 1; + } + + delete ellipse; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipse", BLACK); + c.run(ellipseFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile new file mode 100644 index 000000000..abab16c06 --- /dev/null +++ b/src/tests/testEllipsoid/Makefile @@ -0,0 +1,87 @@ +# Makefile for testEllipsoid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipsoid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipsoid/testEllipsoid.cpp b/src/tests/testEllipsoid/testEllipsoid.cpp new file mode 100644 index 000000000..69d279ebb --- /dev/null +++ b/src/tests/testEllipsoid/testEllipsoid.cpp @@ -0,0 +1,112 @@ +/* + * testEllipsoid.cpp + * + * Usage: ./testEllipsoid + */ + +#include +#include + +using namespace tsgl; + +void ellipsoidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); + // testEllipsoid->setIsFilled(false); + Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); + testEllipsoid2->setOutlineColor(BLUE); + + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(colors); + // printf("%f\n", testEllipsoid->getAlpha()); + can.add(testEllipsoid); + can.add(testEllipsoid2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = true; + bool b2 = true; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { + testEllipsoid->setIsOutlined(b2); + testEllipsoid2->setIsOutlined(b2); + b2 = !b2; + }); + + // testEllipsoid->setXRadius(150); + // testEllipsoid->setYRadius(150); + // testEllipsoid->setZRadius(150); + // testEllipsoid->changeXRadiusBy(140); + // testEllipsoid->changeYRadiusBy(140); + // testEllipsoid->changeZRadiusBy(140); + while (can.isOpen()) { + can.sleep(); + // testEllipsoid->setCenterX(sin(rotation)); + // testEllipsoid->setCenterY(cos(rotation)); + // testEllipsoid->setCenterZ(sin(rotation)); + // testEllipsoid->setYaw(rotation*45); + testEllipsoid->setPitch(rotation*45); + testEllipsoid2->setPitch(rotation*45); + // if(boolean) + // testEllipsoid->setRoll(rotation*45); + // testEllipsoid->setXRadius(cos(rotation) * 100 +101); + // testEllipsoid->setYRadius(sin(rotation) * 100 +201); + // testEllipsoid->setZRadius(sin(rotation) * 100 +301); + // if(testEllipsoid->getXRadius() >= 200) { + // delta = -5; + // } + // if(testEllipsoid->getXRadius() <= 5) { + // delta = 5; + // } + // testEllipsoid->changeXRadiusBy(delta); + + // if(testEllipsoid->getYRadius() >= 500) { + // delta = -5; + // } + // if(testEllipsoid->getYRadius() <= 300) { + // delta = 5; + // } + // testEllipsoid->changeYRadiusBy(delta); + + // if(testEllipsoid->getZRadius() >= 300) { + // delta = -5; + // } + // if(testEllipsoid->getZRadius() <= 100) { + // delta = 5; + // } + // testEllipsoid->changeZRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testEllipsoid->setColor(RED); + } else { + testEllipsoid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testEllipsoid; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid", BLACK); + c.run(ellipsoidFunction); +} \ No newline at end of file diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile new file mode 100644 index 000000000..abf0218da --- /dev/null +++ b/src/tests/testFunction/Makefile @@ -0,0 +1,87 @@ +# Makefile for testFunction + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testFunction + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testFunction.cpp b/src/tests/testFunction/testFunction.cpp similarity index 85% rename from src/tests/testFunction.cpp rename to src/tests/testFunction/testFunction.cpp index 342306715..9026e960c 100644 --- a/src/tests/testFunction.cpp +++ b/src/tests/testFunction/testFunction.cpp @@ -21,13 +21,14 @@ using namespace tsgl; * \param can Reference to the CartesianCanvas being drawn to. */ void functionFunction(CartesianCanvas& can) { - can.drawAxes(0, 0, 1, 5); + CartesianBackground * cart = can.getBackground(); + cart->drawAxes(0, 0, 1, 5); CosineFunction function1; - can.drawFunction(function1,FRAME/5); + cart->drawFunction(function1); PowerFunction function2(2); - can.drawFunction(function2,FRAME/5); + cart->drawFunction(function2); class myFunction : public Function { public: @@ -37,7 +38,7 @@ void functionFunction(CartesianCanvas& can) { }; myFunction function3; - can.drawFunction(function3,FRAME/5); + cart->drawFunction(function3); } //Takes command line arguments for the window width and height @@ -46,7 +47,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 1000; //If not, set the width and height to a default value - Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting"); - c.setBackgroundColor(WHITE); + Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting", WHITE); c.run(functionFunction); } diff --git a/src/tests/testGetColors/Makefile b/src/tests/testGetColors/Makefile new file mode 100644 index 000000000..240f1efb8 --- /dev/null +++ b/src/tests/testGetColors/Makefile @@ -0,0 +1,87 @@ +# Makefile for testGetColors + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGetColors + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGetColors/testGetColors.cpp b/src/tests/testGetColors/testGetColors.cpp new file mode 100644 index 000000000..d34c58945 --- /dev/null +++ b/src/tests/testGetColors/testGetColors.cpp @@ -0,0 +1,203 @@ +/* + * testGetColors.cpp + * + * Usage: ./testGetColors + */ + +#include + +using namespace tsgl; + +bool testArrow(ColorFloat * colors) { + Arrow * arrow = new Arrow(0,0,0,50,50,0,0,0,colors); + std::vector cVec; + arrow->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("a%d ", i); + if (cVec[i] != colors[i]) { + delete arrow; + return false; + } + } + printf("\n"); + delete arrow; + return true; +} + +bool testCircle(ColorFloat * colors) { + Circle * circle = new Circle(0,0,0,50,0,0,0,colors); + std::vector cVec; + circle->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("b%d ", i); + if (cVec[i] != colors[i]) { + delete circle; + return false; + } + } + printf("\n"); + delete circle; + return true; +} + +bool testCube(ColorFloat * colors) { + Cube * cube = new Cube(0,0,0,50,0,0,0,colors); + std::vector cVec; + cube->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("c%d ", i); + if (cVec[i] != colors[i]) { + delete cube; + return false; + } + } + printf("\n"); + delete cube; + return true; +} + +bool testCuboid(ColorFloat * colors) { + Cuboid * cuboid = new Cuboid(0,0,0,50,50,50,0,0,0,colors); + std::vector cVec; + cuboid->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("d%d ", i); + if (cVec[i] != colors[i]) { + delete cuboid; + return false; + } + } + printf("\n"); + delete cuboid; + return true; +} + +bool testEllipse(ColorFloat * colors) { + Ellipse * ellipse = new Ellipse(0,0,0,50,50,0,0,0,colors); + std::vector cVec; + ellipse->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("e%d ", i); + if (cVec[i] != colors[i]) { + delete ellipse; + return false; + } + } + printf("\n"); + delete ellipse; + return true; +} + +bool testEllipsoid(ColorFloat * colors) { + Ellipsoid * ellipsoid = new Ellipsoid(0,0,0,50,50,50,0,0,0,colors); + std::vector cVec; + ellipsoid->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("f%d ", i); + if (cVec[i] != colors[i]) { + delete ellipsoid; + return false; + } + } + printf("\n"); + delete ellipsoid; + return true; +} + +bool testPrism(ColorFloat * colors) { + Prism * prism = new Prism(0,0,0,5,50,50,0,0,0,colors); + std::vector cVec; + prism->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("g%d ", i); + if (cVec[i] != colors[i]) { + delete prism; + return false; + } + } + printf("\n"); + delete prism; + return true; +} + +bool testPyramid(ColorFloat * colors) { + Pyramid * pyramid = new Pyramid(0,0,0,5,50,50,0,0,0,colors); + std::vector cVec; + pyramid->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("h%d ", i); + if (cVec[i] != colors[i]) { + delete pyramid; + return false; + } + } + printf("\n"); + delete pyramid; + return true; +} + +bool testSphere(ColorFloat * colors) { + Sphere * sphere = new Sphere(0,0,0,50,0,0,0,colors); + std::vector cVec; + sphere->getColors(cVec); + for (int i = 0; i < cVec.size(); i++) { + printf("i%d ", i); + if (cVec[i] != colors[i]) { + delete sphere; + return false; + } + } + printf("\n"); + delete sphere; + return true; +} + +bool testOthers(ColorFloat * colors) { + RegularPolygon * rp = new RegularPolygon(0,0,0,50,5,0,0,0,colors); + std::vector cVec1; + rp->getColors(cVec1); + for (int i = 0; i < cVec1.size(); i++) { + printf("j%d ", i); + if (cVec1[i] != colors[i]) { + delete rp; + return false; + } + } + printf("\n"); + delete rp; + std::vector cVec2; + Square * square = new Square(0,0,0,50,0,0,0,colors); + square->getColors(cVec2); + for (int i = 0; i < cVec2.size(); i++) { + printf("k%d ", i); + if (cVec2[i] != colors[i]) { + delete square; + return false; + } + } + printf("\n"); + delete square; + return true; +} + +int main(int argc, char* argv[]) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + tsglAssert(testArrow(colors), "Arrow::getColors assertion failed."); + tsglAssert(testCircle(colors), "Circle::getColors assertion failed."); + tsglAssert(testCube(colors), "Cube::getColors assertion failed."); + tsglAssert(testCuboid(colors), "Cuboid::getColors assertion failed."); + tsglAssert(testEllipse(colors), "Ellipse::getColors assertion failed."); + tsglAssert(testEllipsoid(colors), "Ellipsoid::getColors assertion failed."); + tsglAssert(testPrism(colors), "Prism::getColors assertion failed."); + tsglAssert(testPyramid(colors), "Pyramid::getColors assertion failed."); + tsglAssert(testSphere(colors), "Sphere::getColors assertion failed."); + tsglAssert(testOthers(colors), "Others::getColors assertion failed."); + printf("All tests passed!\n"); +} \ No newline at end of file diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile new file mode 100644 index 000000000..157516953 --- /dev/null +++ b/src/tests/testGetPixels/Makefile @@ -0,0 +1,87 @@ +# Makefile for testGetPixels + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGetPixels + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp similarity index 76% rename from src/tests/testGetPixels.cpp rename to src/tests/testGetPixels/testGetPixels.cpp index a3b2e55e9..60e853298 100644 --- a/src/tests/testGetPixels.cpp +++ b/src/tests/testGetPixels/testGetPixels.cpp @@ -36,19 +36,20 @@ using namespace tsgl; * \param threads Number of threads to use. */ void getPixelsFunction(Canvas& can, int threads) { - unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); - can.drawImage("../assets/pics/test.png", 0, 0, width, height); + Background * bg = can.getBackground(); + int width = can.getWindowWidth(), height = can.getWindowHeight(); + bg->drawImage(0,0,0,"./assets/pics/test.png",width, height, 0,0,0); can.sleepFor(0.5f); #pragma omp parallel num_threads(threads) { - unsigned blocksize = (double)height / omp_get_num_threads(); - unsigned row = blocksize * omp_get_thread_num(); + int blocksize = (double)height / omp_get_num_threads(); + int row = blocksize * omp_get_thread_num() - can.getWindowHeight()/2; while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (unsigned y = row; y < row + blocksize; y++) { - for (unsigned x = 0; x < width; x++) { - ColorInt c = can.getPoint(x,y); - can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); + for (int y = row; y < row + blocksize; y++) { + for (int x = -(width/2); x < width/2; x++) { + ColorInt c = bg->getPixel(x,y); + bg->drawPixel(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); } } } diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile new file mode 100644 index 000000000..6e4282003 --- /dev/null +++ b/src/tests/testGradientWheel/Makefile @@ -0,0 +1,87 @@ +# Makefile for testGradientWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGradientWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGradientWheel.cpp b/src/tests/testGradientWheel/testGradientWheel.cpp similarity index 79% rename from src/tests/testGradientWheel.cpp rename to src/tests/testGradientWheel/testGradientWheel.cpp index 8eddde4da..44c3caaa0 100644 --- a/src/tests/testGradientWheel.cpp +++ b/src/tests/testGradientWheel/testGradientWheel.cpp @@ -22,6 +22,7 @@ using namespace tsgl; * \param threads Number of threads to use. */ void gradientWheelFunction(Canvas& can, int threads) { + Background * background = can.getBackground(); const int CW = can.getWindowWidth() / 2, // Half the window's width CH = can.getWindowHeight() / 2; // Half the window's height const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel @@ -33,7 +34,8 @@ void gradientWheelFunction(Canvas& can, int threads) { int delta = (NUM_COLORS / threads); // Distance between threads to compute float shading = 1 - (float)tid / threads; // Shading based on thread ID ColorFloat color[3]; // RGB color to build - int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices + int start, end; + float xx[3], yy[3], zz[3]; // Setup the arrays of values for vertices while (can.isOpen()) { can.sleep(); start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment @@ -42,13 +44,14 @@ void gradientWheelFunction(Canvas& can, int threads) { color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen - xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle - yy[1] = CH + RADIUS * cos(ARCLENGTH * start); - xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); - yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); + xx[0] = 0; yy[0] = 0; // Set first vertex to center of screen + xx[1] = RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle + yy[1] = RADIUS * cos(ARCLENGTH * start); + xx[2] = RADIUS * sin(ARCLENGTH * (start + 1)); + yy[2] = RADIUS * cos(ARCLENGTH * (start + 1)); + zz[0] = zz[1] = zz[2] = 0; - can.drawTriangleStrip(3, xx, yy, color, true); + background->drawTriangleStrip(0,0,0,3,xx,yy,zz,0,0,0,color); } } } @@ -60,7 +63,6 @@ int main(int argc, char* argv[]) { if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid w = h = 960; // If not, set the width and height to a default value int t = (argc > 3) ? atoi(argv[3]) : 256; - Canvas c(-1, -1, w, h, "Gradient Color Wheel"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Gradient Color Wheel", BLACK); c.run(gradientWheelFunction,t); } diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile new file mode 100644 index 000000000..6915cc422 --- /dev/null +++ b/src/tests/testGraydient/Makefile @@ -0,0 +1,87 @@ +# Makefile for testGraydient + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGraydient + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGraydient.cpp b/src/tests/testGraydient/testGraydient.cpp similarity index 78% rename from src/tests/testGraydient.cpp rename to src/tests/testGraydient/testGraydient.cpp index 4d3a2af77..4f5dfe0fa 100644 --- a/src/tests/testGraydient.cpp +++ b/src/tests/testGraydient/testGraydient.cpp @@ -25,13 +25,14 @@ using namespace tsgl; * \param threads Number of threads to use. */ void graydientFunction(Canvas& can, int threads) { + Background * bg = can.getBackground(); #pragma omp parallel num_threads(threads) { - for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { + for (int i = omp_get_thread_num() - (can.getWindowWidth() / 2); i < (can.getWindowWidth() / 2); i += omp_get_num_threads()) { if (!can.isOpen()) break; - for (int j = 0; j < can.getWindowHeight(); j++) { - int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); - can.drawPoint(i, j, ColorInt(color, color, color)); + for (int j = -can.getWindowHeight()/2; j < can.getWindowHeight()/2; j++) { + int color = (i + can.getWindowWidth() / 2) * MAX_COLOR / 2 / can.getWindowWidth() + (j + can.getWindowHeight()/2) * MAX_COLOR / 2 / can.getWindowHeight(); + bg->drawPixel(i, j, ColorInt(color, color, color)); } can.sleep(); } diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile new file mode 100644 index 000000000..ef0fb1b04 --- /dev/null +++ b/src/tests/testGreyscale/Makefile @@ -0,0 +1,87 @@ +# Makefile for testGreyscale + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGreyscale + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGreyscale.cpp b/src/tests/testGreyscale/testGreyscale.cpp similarity index 76% rename from src/tests/testGreyscale.cpp rename to src/tests/testGreyscale/testGreyscale.cpp index f62b7cfbc..76dfb5bbb 100644 --- a/src/tests/testGreyscale.cpp +++ b/src/tests/testGreyscale/testGreyscale.cpp @@ -45,31 +45,33 @@ using namespace tsgl; * \param numberOfThreads Reference to the number of threads to use. */ void greyScaleFunction(Canvas& can, int numberOfThreads) { + Background * background = can.getBackground(); int threads = numberOfThreads; clamp(threads,1,30); const unsigned thickness = 3; - const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); - can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); + const int WW = can.getWindowWidth(),WH = can.getWindowHeight(); + background->drawImage(0,0,0,"./assets/pics/colorful_cars.jpg", WW, WH, 0,0,0); can.sleepFor(0.25f); #pragma omp parallel num_threads(threads) { int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); + int blocksize = WH / nthreads; + int row = blocksize * omp_get_thread_num() - WH / 2; ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); - for (unsigned int y = row; y < row + blocksize; y++) { - for (unsigned int x = 0; x < WW; x++) { - ColorInt pixelColor = can.getPoint(x, y); + color.A = 0.6; + for (int y = row; y < row + blocksize; y++) { + for (int x = -WW / 2; x < WW / 2; x++) { + ColorInt pixelColor = background->getPixel(x, y); int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; - can.drawPoint(x, y, ColorInt(gray, gray, gray)); + background->drawPixel(x, y, ColorInt(gray, gray, gray)); } if (! can.isOpen()) break; can.sleep(); } - for (unsigned int i = 0; i < thickness; i++) { - can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); - // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); - } + background->drawRectangle(0, row + (float)thickness/2, 1, WW, thickness, 0,0,0, color); + background->drawRectangle(0, row + blocksize - (float)thickness/2, 1, WW, thickness, 0,0,0, color); + background->drawRectangle(-WW/2 + (float)thickness/2, row + blocksize/2, 1, thickness, blocksize, 0,0,0, color); + background->drawRectangle(WW/2 - (float)thickness/2, row + blocksize/2, 1, thickness, blocksize, 0,0,0, color); } } diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile new file mode 100644 index 000000000..6548f2065 --- /dev/null +++ b/src/tests/testHighData/Makefile @@ -0,0 +1,87 @@ +# Makefile for testHighData + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testHighData + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testHighData.cpp b/src/tests/testHighData/testHighData.cpp similarity index 82% rename from src/tests/testHighData.cpp rename to src/tests/testHighData/testHighData.cpp index 43ce27f05..744505b42 100644 --- a/src/tests/testHighData.cpp +++ b/src/tests/testHighData/testHighData.cpp @@ -24,20 +24,21 @@ using namespace tsgl; * \param threads Number of threads to use. */ void highData(Canvas& can, unsigned threads) { + Background * background = can.getBackground(); const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values - const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); + const int width = can.getWindowWidth(), height = can.getWindowHeight(); #pragma omp parallel num_threads(threads) { float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); int offset = (MAX_COLOR*tid)/nthreads; - unsigned bstart = tid*(width/nthreads); - unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; + int bstart = tid*(width/nthreads) - width/2; + int bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; ColorHSV tcol= Colors::highContrastColor(tid); while (can.isOpen()) { tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); - for (unsigned i = bstart; i <= bend; i++) - for (unsigned int j = 0; j < height; j++) - can.drawPoint(i, j, tcol); + for (int i = bstart; i <= bend; i++) + for (int j = -height/2; j < height/2; j++) + background->drawPixel(i, j, tcol); can.handleIO(); } } diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp deleted file mode 100644 index d9af717aa..000000000 --- a/src/tests/testImage.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * testImage.cpp - * - * Usage: ./testImage - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a Canvas. - * \details Very basic test function showcasing image drawing capabilities. - * - The first 6 images are drawn opaque. - * - The 7th image is drawn across the entire Canvas with alpha transparency. - * . - * \param can Reference to the Canvas being drawn to. - */ -void imageFunction(Canvas& can) { - int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; - can.drawImage("../assets/pics/test.png", 0, 0, ww, hh); - can.drawImage("../assets/pics/ship.bmp", ww, 0, ww, hh); // possibly lost - can.drawImage("../assets/pics/shiprgb.bmp", ww*2, 0, ww, hh); // definitely lost - can.drawImage("../assets/pics/sky_main.jpg", 0, hh, ww, hh); - can.drawImage("../assets/pics/colorfulKeyboard.jpg", ww, hh, ww, hh); - can.drawImage("../assets/pics/cow.jpg", ww*2, hh, ww, hh); - - can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; - } - Canvas c(-1, -1, w, h ,"Images"); - c.run(imageFunction); -} diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile new file mode 100644 index 000000000..a4b4d8558 --- /dev/null +++ b/src/tests/testImage/Makefile @@ -0,0 +1,86 @@ +# Makefile for testImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImage/testImage.cpp b/src/tests/testImage/testImage.cpp new file mode 100644 index 000000000..3de6187c7 --- /dev/null +++ b/src/tests/testImage/testImage.cpp @@ -0,0 +1,101 @@ +/* + * testImage.cpp + * + * Usage: ./testImage + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a Canvas. + * \details Very basic test function showcasing image drawing capabilities. + * - The first 6 images are drawn opaque. + * - The 7th image is drawn across the entire Canvas with alpha transparency. + * . + * \param can Reference to the Canvas being drawn to. + */ +void imageFunction(Canvas& can) { + int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; + // Square * s = new Square(5,0,0,50,0,0,0,RED); + // can.add(s); + + // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); + // can.add(p); + + // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); + // can.add(image); + + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); + can.add(image); + Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); + can.add(image2); + Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); + can.add(image3); + Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); + can.add(image4); + Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); + can.add(image5); + Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); + can.add(image6); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { + image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); + }); + + // image->setHeight((GLfloat)image->getPixelHeight()); + // image->setWidth((GLfloat)image->getPixelWidth()); + + float floatVal = 0.0f; + GLfloat delta = 5; + bool ss = false; + while (can.isOpen()) { + can.sleep(); + image->setAlpha((sin(floatVal) + 1) / 2); + // image->setCenterX(sin(floatVal/90) * 100); + // image->setCenterY(sin(floatVal/90) * 100); + // image->setCenterZ(sin(floatVal/90) * 100); + // image->setYaw(floatVal); + image->setPitch(floatVal * 100); + // image->setRoll(floatVal); + // image->setWidth(sin(floatVal/90) * 100 + 400); + // image->setHeight(sin(floatVal/90) * 100 + 400); + // if (image->getWidth() > 500 || image->getWidth() < 300) { + // delta *= -1; + // } + // image->changeWidthBy(delta); + // if (image->getHeight() > 500 || image->getHeight() < 300) { + // delta *= -1; + // } + // image->changeHeightBy(delta); + // printf("%d\n", can.getFrameNumber()); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); + // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); + floatVal += 0.01; + } + + // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay + + delete image; + delete image2; + delete image3; + delete image4; + delete image5; + delete image6; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; + } + Canvas c(-1, -1, w, h ,"Images", WHITE); + c.run(imageFunction); +} diff --git a/src/tests/testImageCart.cpp b/src/tests/testImageCart.cpp deleted file mode 100644 index a7e4aead0..000000000 --- a/src/tests/testImageCart.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * testImageCart.cpp - * - * Usage: ./testImageCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a CartesianCanvas. - * \details Same as imageFunction, but on a CartesianCanvas. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - */ -void imageCartFunction(Cart& can) { - can.drawImage("../assets/pics/test.png", 0, 3, 2, 1.5); - can.drawImage("../assets/pics/ship.bmp", 2, 3, 2, 1.5); // possibly lost - can.drawImage("../assets/pics/shiprgb.bmp", 4, 3, 2, 1.5); // definitely lost - can.drawImage("../assets/pics/sky_main.jpg", 0, 1.5, 2, 1.5); - can.drawImage("../assets/pics/cow.jpg", 2, 1.5, 2, 1.5); - can.drawImage("../assets/pics/colorfulKeyboard.jpg", 4, 1.5, 2, 1.5); - - can.drawImage("../assets/pics/colorful-cars-circle.jpg", 1, 3, 4, 3, 0.25f); //Overlay -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.5 * w; - } - Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); - c.run(imageCartFunction); -} diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile new file mode 100644 index 000000000..319fe89f1 --- /dev/null +++ b/src/tests/testImageCart/Makefile @@ -0,0 +1,87 @@ +# Makefile for testImageCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImageCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImageCart/testImageCart.cpp b/src/tests/testImageCart/testImageCart.cpp new file mode 100644 index 000000000..e33994945 --- /dev/null +++ b/src/tests/testImageCart/testImageCart.cpp @@ -0,0 +1,49 @@ +/* + * testImageCart.cpp + * + * Usage: ./testImageCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a CartesianCanvas. + * \details Same as imageFunction, but on a CartesianCanvas. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + */ +void imageCartFunction(Cart& can) { + CartesianBackground * cart = can.getBackground(); + cart->drawImage(1, 2.25, 0, "./assets/pics/test.png", 2, 1.5, 0,0,0); + cart->drawImage(3, 2.25, 0, "./assets/pics/ship.bmp", 2, 1.5, 0,0,0); // possibly lost + cart->drawImage(5, 2.25, 0, "./assets/pics/shiprgb.bmp", 2, 1.5, 0,0,0); // definitely lost + cart->drawImage(1, 0.75, 0, "./assets/pics/sky_main.jpg", 2, 1.5, 0,0,0); + cart->drawImage(3, 0.75, 0, "./assets/pics/cow.jpg", 2, 1.5, 0,0,0); + cart->drawImage(5, 0.75, 0, "./assets/pics/colorfulKeyboard.jpg", 2, 1.5, 0,0,0); + + Image * image = new Image(3, 1.5, 0, "./assets/pics/colorful-cars-circle.jpg", 4, 3, 0,0,0, 0.25f); + can.add(image); + + // Arrow * a = new Arrow(1, 2, 0, 5, 1, 0, 0.1, 0,0,0, BLUE); + // can.add(a); + + while (can.isOpen()) { + can.sleep(); + } + + delete image; + // delete a; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2 * Canvas::getDisplayHeight(); + h = 0.5 * w; + } + Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); + c.run(imageCartFunction); +} diff --git a/src/tests/ImageInverter/ImageInverter.cpp b/src/tests/testInverter/ImageInverter.cpp similarity index 64% rename from src/tests/ImageInverter/ImageInverter.cpp rename to src/tests/testInverter/ImageInverter.cpp index f559065b1..c13478f3d 100644 --- a/src/tests/ImageInverter/ImageInverter.cpp +++ b/src/tests/testInverter/ImageInverter.cpp @@ -10,7 +10,7 @@ ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsign myWidth(width), myHeight(height), myFileName(fileName) { myCanvas1.start(); - myCanvas1.drawImage(fileName, 0, 0, width, height); + myCanvas1.getBackground()->drawImage(0,0,0,fileName,width, height,0,0,0); // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); sleep(1); myCanvas2.start(); @@ -22,21 +22,24 @@ void ImageInverter::run(unsigned numThreads) { } void ImageInverter::invertImage(unsigned numThreads) { + Background * background1 = myCanvas1.getBackground(); + Background * background2 = myCanvas2.getBackground(); + // background2->drawSquare(0,0,0,50,0,0,0,RED); ColorInt pixelColor; // #pragma omp parallel for num_threads(numThreads) - const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); + const int WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); #pragma omp parallel num_threads(numThreads) { int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - for (unsigned int x = row; x < row + blocksize; x++) { - for (unsigned int y = 0; y < WW; y++) { - pixelColor = myCanvas1.getPixel(x, y); + int blocksize = WW / nthreads; + int row = blocksize * omp_get_thread_num() - WW/2; + for (int x = row; x < row + blocksize; x++) { + for (int y = -WH/2; y < WH/2; y++) { + pixelColor = background1->getPixel(x, y); int invertedR = 255 - pixelColor.R; int invertedG = 255 - pixelColor.G; int invertedB = 255 - pixelColor.B; - myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); + background2->drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); } myCanvas1.sleep(); myCanvas2.sleep(); diff --git a/src/tests/ImageInverter/ImageInverter.h b/src/tests/testInverter/ImageInverter.h similarity index 100% rename from src/tests/ImageInverter/ImageInverter.h rename to src/tests/testInverter/ImageInverter.h diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile new file mode 100644 index 000000000..2f1454887 --- /dev/null +++ b/src/tests/testInverter/Makefile @@ -0,0 +1,87 @@ +# Makefile for testInverter + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testInverter + +# Object files +ODIR = obj +_OBJ = ImageInverter.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testInverter.cpp b/src/tests/testInverter/testInverter.cpp similarity index 69% rename from src/tests/testInverter.cpp rename to src/tests/testInverter/testInverter.cpp index 370b4f62f..d94245150 100644 --- a/src/tests/testInverter.cpp +++ b/src/tests/testInverter/testInverter.cpp @@ -5,12 +5,12 @@ */ #include -#include "ImageInverter/ImageInverter.h" +#include "ImageInverter.h" using namespace tsgl; int main(int argc, char* argv[]) { int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); + ImageInverter ii("./assets/pics/Car-colors.jpg", 1022, 1024); ii.run(numThreads); } diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile new file mode 100644 index 000000000..09cc07d94 --- /dev/null +++ b/src/tests/testLineChain/Makefile @@ -0,0 +1,87 @@ +# Makefile for testLineChain + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineChain + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineChain.cpp b/src/tests/testLineChain/testLineChain.cpp similarity index 90% rename from src/tests/testLineChain.cpp rename to src/tests/testLineChain/testLineChain.cpp index 13b92ce7c..e9dd210a2 100644 --- a/src/tests/testLineChain.cpp +++ b/src/tests/testLineChain/testLineChain.cpp @@ -39,6 +39,7 @@ using namespace tsgl; * \param t The number of threads to use in the function. */ void lineChainFunction(Canvas& can, int t) { + Background * bg = can.getBackground(); const int IPF = 3; const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; const float ARC = 2.3f, SPIN = 0.01f; @@ -47,7 +48,7 @@ void lineChainFunction(Canvas& can, int t) { const float NTHREADS = omp_get_num_threads(); const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; const int TID = omp_get_thread_num(); - int xOld, yOld, xNew = CWW*2, yNew = CWH; + int xOld, yOld, xNew = CWW, yNew = 0; float next = (ARC*TID)/NTHREADS, s = next; ColorFloat c = Colors::highContrastColor(TID); while (can.isOpen()) { // Checks to see if the window has been closed @@ -56,12 +57,12 @@ void lineChainFunction(Canvas& can, int t) { next += ARC; s += SPIN; xOld = xNew; yOld = yNew; float size = cos(s); - xNew = CWW + CWW*size*cos(next); - yNew = CWH + CWH*size*sin(next); - can.drawLine(xOld, yOld, xNew, yNew, c); + xNew = CWW*size*cos(next); + yNew = CWH*size*sin(next); + bg->drawLine(xOld, yOld, 0, xNew, yNew, 0, 0,0,0, c); } if (TID == 0) - can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); + bg->drawRectangle(0,0,0,CWW*2,CWH*2,0,0,0,ColorFloat(0,0,0,FADERATE)); #pragma omp barrier } } @@ -77,7 +78,6 @@ int main(int argc, char* argv[]) { unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use if (t == 0) t = omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Spirograph"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Spirograph", BLACK); c.run(lineChainFunction,t); } diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile new file mode 100644 index 000000000..202202d4a --- /dev/null +++ b/src/tests/testLineFan/Makefile @@ -0,0 +1,86 @@ +# Makefile for testLineFan + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineFan + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineFan.cpp b/src/tests/testLineFan/testLineFan.cpp similarity index 88% rename from src/tests/testLineFan.cpp rename to src/tests/testLineFan/testLineFan.cpp index 74aaf0d4a..71dc78d58 100644 --- a/src/tests/testLineFan.cpp +++ b/src/tests/testLineFan/testLineFan.cpp @@ -29,22 +29,21 @@ using namespace tsgl; * \param t The number of threads to use in the function. */ void lineFanFunction(Canvas& can, int t) { + Background * bg = can.getBackground(); const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan while (can.isOpen()) { #pragma omp parallel num_threads(t) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - int a, b, c, d, red, green, blue; - double angle, offset = omp_get_thread_num() * ARC; - angle = offset + can.getReps() * RAD; + int a, b, red, green, blue; + double angle, offset = omp_get_thread_num() * ARC * 180 / PI; + angle = offset + can.getReps(); a = can.getWindowWidth() / 2 * (1 + sin(angle)); b = can.getWindowHeight() / 2 * (1 + cos(angle)); - c = can.getWindowWidth() / 2 * (1 - sin(angle)); - d = can.getWindowHeight() / 2 * (1 - cos(angle)); red = (a + can.getReps()) % NUM_COLORS; green = (b + can.getReps()) % NUM_COLORS; blue = (a * b + can.getReps()) % NUM_COLORS; - can.drawLine(a, b, c, d, ColorInt(red, green, blue)); + bg->drawLine(0, 0, 0, can.getWindowHeight() * 0.9, angle, 0,0, ColorInt(red, green, blue)); } } } diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile new file mode 100644 index 000000000..3e8c8fb4d --- /dev/null +++ b/src/tests/testLines/Makefile @@ -0,0 +1,87 @@ +# Makefile for testLines + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLines + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp new file mode 100644 index 000000000..9b7774184 --- /dev/null +++ b/src/tests/testLines/testLines.cpp @@ -0,0 +1,85 @@ +/** + * testLines.cpp tests displaying the Line and Polyline classes. + */ +#include +using namespace tsgl; + +void lineFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), + ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), + ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), + ColorFloat(0,0,1,0.7) }; + Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); + + // l->setColor(RED); + l->setColor(colors); + + float vertices[] = { -150,-100,-100, + -100,100,0, + -50,-100,100, + 0,-100,-100, + 50,100,0, + 100,-100,100, + 150,-100,-100 }; + + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); + + Line * l2 = new Line(-250, -250, -100, -150, 200, 100, 0,0,0, colors); + // printf("Line: %f\n", l->getAlpha()); + // printf("Pline: %f\n", p->getAlpha()); + + c.bindToButton(TSGL_SPACE, TSGL_PRESS, [&l2] () { + // l2->setFirstEndpoint(-250, -250, -100); + printf("%f\n", l2->getLength()); + }); + + // p->setColor(BLUE); + // p->setColor(colors); + c.add(l); + c.add(p); + c.add(l2); + float floatVal = 0.0f; + GLfloat delta = 5; + while( c.isOpen() ) { + c.sleep(); + // l->setCenterX(sin(floatVal/90)); + // l->setCenterY(sin(floatVal/90)); + // l->setCenterZ(sin(floatVal/90)); + // l->setYaw(floatVal); + // l->setPitch(floatVal); + // l->setRoll(floatVal); + // printf("1: %f, %f, %f\n", l->getFirstEndpointX(),l->getFirstEndpointY(),l->getFirstEndpointZ()); + // printf("2: %f, %f, %f\n", l->getSecondEndpointX(),l->getSecondEndpointY(),l->getSecondEndpointZ()); + // l->setLength(100 * sin(floatVal/90) + 200); + // if (l->getLength() > 300 || l->getLength() < 100) { + // delta *= -1; + // } + // l->changeLengthBy(delta); + // p->setCenterX(sin(floatVal/90)); + // p->setCenterY(sin(floatVal/90)); + // p->setCenterZ(sin(floatVal/90)); + // p->setYaw(floatVal); + // p->setPitch(floatVal); + // p->setRoll(floatVal); + // l2->setFirstEndpoint(-250,-250 * cos((float) c.getFrameNumber()/180),-100); + // l2->setSecondEndpoint(-150,200 * cos((float) c.getFrameNumber()/180),100); + // l2->setLength(350 + 150 * cos(floatVal/90)); + // if (l2->getLength() > 500 || l2->getLength() < 300) { + // delta *= -1; + // } + // l2->changeLengthBy(delta); + // printf("%f, %f, %f - %f, %f, %f\n",l2->getFirstEndpointX(),l2->getFirstEndpointY(),l2->getFirstEndpointZ(),l2->getSecondEndpointX(),l2->getSecondEndpointY(),l2->getSecondEndpointZ()); + floatVal += 1; + } + + delete l; + delete p; + delete l2; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 600; + Canvas c(-1, -1, w, h, "Lines"); + c.run(lineFunction); +} \ No newline at end of file diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile new file mode 100644 index 000000000..36b551c86 --- /dev/null +++ b/src/tests/testMouse/Makefile @@ -0,0 +1,87 @@ +# Makefile for testMouse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMouse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testMouse.cpp b/src/tests/testMouse/testMouse.cpp similarity index 80% rename from src/tests/testMouse.cpp rename to src/tests/testMouse/testMouse.cpp index 5d30116a3..95f9520e4 100644 --- a/src/tests/testMouse.cpp +++ b/src/tests/testMouse/testMouse.cpp @@ -16,13 +16,13 @@ inline float angle(float x1, float y1, float x2, float y2) { return atan2(y1 - y2, x1 - x2); } -inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { +inline void rotate(float cx, float cy, float& xx, float& yy, float rot) { float scale = cy/cx; - float stretchy = cy + yy/scale - cx; - float mydist = dist(xx,stretchy,cx,cy); - float newang = angle(xx,stretchy,cx,cy)+rot; - xx = cx + mydist*cos(newang); - yy = cy + mydist*sin(newang)*scale; + float stretchy = yy/scale; + float mydist = dist(xx,stretchy,0,0); + float newang = angle(xx,stretchy,0,0)+rot; + xx = mydist*cos(newang); + yy = mydist*sin(newang)*scale; } /*! @@ -53,13 +53,14 @@ inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { * \param threads Number of threads to use. */ void mouseFunction(Canvas& can, int threads) { - const int CX = can.getWindowWidth() / 2, CY = can.getWindowHeight() / 2; + Background * bg = can.getBackground(); + const int CX = can.getWindowWidth(), CY = can.getWindowHeight(); int x[3], y[3], index = 0; bool mouseDown = false; ColorFloat color[3]; - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg]() { + bg->clear(); }); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown, &can, &index, &x, &y, &color]() { x[0] = can.getMouseX(); @@ -82,12 +83,15 @@ void mouseFunction(Canvas& can, int threads) { #pragma omp parallel num_threads (threads) { float tdelta = (2*PI*omp_get_thread_num())/omp_get_num_threads(); - int myx[3], myy[3]; + float myx[3], myy[3]; + float cx = 0, cy = 0, cz = 0; for (int i = 0; i < 3; ++i) { myx[i] = x[i]; myy[i] = y[i]; rotate(CX,CY,myx[i],myy[i],tdelta); + cx += myx[i]; cy += myy[i]; } - can.drawConvexPolygon(3,myx,myy,color,true); + cx /= 3; cy /= 3; + bg->drawConvexPolygon(cx,cy,0,3,myx,myy,0,0,0,color); } } can.sleep(); @@ -98,7 +102,6 @@ int main(int argc, char* argv[]) { int w = (argc > 1) ? atoi(argv[1]) : -1; int h = (argc > 2) ? atoi(argv[2]) : w; int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Draw With Your Mouse!"); - c.setBackgroundColor(WHITE); + Canvas c(-1, -1, w, h, "Draw With Your Mouse!", WHITE); c.run(mouseFunction,t); } diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile new file mode 100644 index 000000000..e87fc641f --- /dev/null +++ b/src/tests/testPixels/Makefile @@ -0,0 +1,87 @@ +# Makefile for testPixels + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPixels + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp new file mode 100644 index 000000000..41e2b367a --- /dev/null +++ b/src/tests/testPixels/testPixels.cpp @@ -0,0 +1,103 @@ +/* + * testColorPoints.cpp + * + * Usage: ./testColorPoints + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line + * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. + * - The actual number of threads created is stored in: \b nthreads . + * - The number of lines per thread is calculated and stored in: \b myPart . + * - The starting position of each given thread is calculated and stored in: \b myStart . + * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. + * - The color for a thread is calculated. + * - If the point's coordinate is even: + * - Draw a point on the Canvas in the thread's color. + * - Else: + * - Draw the point normally. + * . + * - The function breaks from the outer for loop if the Canvas is closed. + * . + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Number of threads to use. + */ +void colorPointsFunction(Canvas& can, int numberOfThreads) { + // Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); + // can.setBackground(background); + Background * background = can.getBackground(); + + /* this is the part of the test for drawPixel */ + #pragma omp parallel num_threads(numberOfThreads) + { + int nthreads = omp_get_num_threads(); //Actual number of threads to use + // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. + // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. + int myPart = can.getWindowHeight() / nthreads; + int myStart = myPart * omp_get_thread_num(); + for (int i = myStart; i < myStart + myPart; i++) { + for (int j = 0; j < can.getWindowWidth(); j++) { + // int id = omp_get_thread_num(); + if (i % 2 == 0) { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(0,0,0,255)); + } else { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(i % 255, j % 255, (i*j) % 255)); + } + } + if (!can.isOpen()) break; + } + } + + /* end drawPixel. while loop only contains can.sleep() */ + + /* the getPixel portion of the test */ + // bool print = false; + // float mouseX = 0; + // float mouseY = 0; + + // background->drawSquare(-100,100,0,100,0,0,0,RED); + // background->drawSquare(-100,-100,0,100,0,0,0,GREEN); + // background->drawSquare(100,100,0,100,0,0,0,BLUE); + // background->drawSquare(100,-100,0,100,0,0,0,ORANGE); + + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { + // print = true; + // }); + + // ColorInt c; + /* end getPixel(). uncomment entirety of while loop besides can.sleep */ + + while (can.isOpen()) { + can.sleep(); + // mouseX = can.getMouseX(); + // mouseY = can.getMouseY(); + // if (print) { + // c = background->getPixel(mouseX, mouseY); + // background->drawPixel(mouseX, mouseY, ColorInt(255,0,0,255)); + // printf("%f, %f - ", mouseX, mouseY); + // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); + // print = false; + // } + } +} + +//Takes in command line arguments for the window width and height as well +//as for the number of threads to use +int main(int argc, char* argv[]) { + int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); + int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Dithered Points", BLACK); + c.run(colorPointsFunction,t); +} diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile new file mode 100644 index 000000000..b30120406 --- /dev/null +++ b/src/tests/testPrism/Makefile @@ -0,0 +1,87 @@ +# Makefile for testPrism + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPrism + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPrism/testPrism.cpp b/src/tests/testPrism/testPrism.cpp new file mode 100644 index 000000000..3be365eff --- /dev/null +++ b/src/tests/testPrism/testPrism.cpp @@ -0,0 +1,84 @@ +/* + * testPrism.cpp + * + * Usage: ./testPrism + */ + +#include +#include + +using namespace tsgl; + +void prismFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); + + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(colors); + // printf("%f\n", testPrism2->getAlpha()); + can.add(testPrism); + can.add(testPrism2); + can.add(testPrism3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPrism->setCenterX(sin(rotation)*200); + // testPrism->setCenterY(cos(rotation)*200); + // testPrism->setCenterZ(sin(rotation)*100); + // testPrism->setYaw(rotation*45); + testPrism->setPitch(rotation*45); + // testPrism->setRoll(rotation*45); + // testPrism->setHeight(sin(rotation)*100+101); + // testPrism->setRadius(sin(rotation)*100+101); + // if(testPrism->getHeight() >= 200) { + // delta = -5; + // } + // if(testPrism->getHeight() <= 5) { + // delta = 5; + // } + // testPrism->changeHeightBy(delta); + // if(testPrism->getRadius() >= 200) { + // delta = -5; + // } + // if(testPrism->getRadius() <= 5) { + // delta = 5; + // } + // testPrism->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testPrism->setColor(RED); + } else { + testPrism->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPrism; + delete testPrism2; + delete testPrism3; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Prism", BLACK); + c.run(prismFunction); +} \ No newline at end of file diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile new file mode 100644 index 000000000..71e299c41 --- /dev/null +++ b/src/tests/testProcedural/Makefile @@ -0,0 +1,87 @@ +# Makefile for testProcedural + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProcedural + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProcedural/testProcedural.cpp b/src/tests/testProcedural/testProcedural.cpp new file mode 100644 index 000000000..2fe19cfc3 --- /dev/null +++ b/src/tests/testProcedural/testProcedural.cpp @@ -0,0 +1,125 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include + +using namespace tsgl; + +void testSuite1(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawSquare(-400, 225, 0, 100, 0,0,0, RED); + bg->drawSquare(-400, 100, 0, 100, 0,0,0, colors); + bg->drawCircle(-400, -100, 0, 50, 0,0,0, RED); + bg->drawCircle(-400, -225, 0, 50, 0,0,0, colors); + bg->drawEllipse(-225, 225, 0, 75,50, 0,0,0, RED); + bg->drawEllipse(-225, 100, 0, 75,50, 0,0,0, colors); + bg->drawRectangle(-225, -100, 0, 150,100, 0,0,0, RED); + bg->drawRectangle(-225, -225, 0, 150,100, 0,0,0, colors); + bg->drawImage(0,225,0,"./assets/pics/launch.bmp",100,100,0,0,0); + bg->drawText(0,100,0,L"ü^xdog","./assets/freefont/FreeMono.ttf",50,0,0,0,RED); + bg->drawRegularPolygon(0,-100,0,50,5,0,0,0,RED); + bg->drawRegularPolygon(0,-225,0,50,7,0,0,0,colors); + bg->drawTriangle(225,275,0,275,175,0,175,175,0,0,0,0,RED); + bg->drawTriangle(225,50,0,275,150,0,175,150,0,0,0,0,colors); + float x1[4] = { 160, 225, 225, 290 }; + float y1[4] = {-100, -50,-150,-100 }; + float z1[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-100,0,4,x1,y1,z1,0,0,0,RED); + float x2[4] = { 160, 225, 225, 290 }; + float y2[4] = {-225,-175,-275,-225 }; + float z2[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-225,0,4,x2,y2,z2,0,0,0,colors); + bg->drawArrow(400,225,0,100,10,45,0,0,RED,true); + bg->drawArrow(400,100,0,100,10,-45,0,0,colors); + bg->drawLine(400,-50,0,100,20,0,0,RED); + bg->drawLine(400,-150,0,100,-20,0,0,colors); + float vertices1[12] = { 350,-175,0, + 350,-200,0, + 450,-250,0, + 450,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices1,0,0,0,RED); + float vertices2[12] = { 450,-175,0, + 450,-200,0, + 350,-250,0, + 350,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices2,0,0,0,colors); +} + +void testSuite2(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawStar(-400,225,0,50,5,0,0,0,RED,false); + bg->drawStar(-400,100,0,50,7,0,0,0,colors,false); + float x1[6] = { -450,-400,-375,-350,-400,-450 }; + float y1[6] = { -50, -50, -60,-150,-150,-100 }; + // renders incorrectly + bg->drawConcavePolygon(-400,-100,0,6,x1,y1,0,0,0,RED); + float x2[6] = { -450,-400,-375,-350,-400,-450 }; + float y2[6] = { -175,-175,-185,-275,-275,-225 }; + // renders correctly, due to shifted vertices + bg->drawConcavePolygon(-400,-225,0,6,x2,y2,0,0,0,colors); + float x3[6] = { -275,-175,-200,-175,-275,-250 }; + float y3[6] = { 275, 275, 225, 175, 175, 225 }; + bg->drawConvexPolygon(-400,225,0,6,x3,y3,0,0,0,RED); + float x4[6] = { -250,-275,-175,-200,-175,-275 }; + float y4[6] = { 100, 150, 150, 100, 50, 50 }; + bg->drawConvexPolygon(-400,100,0,6,x4,y4,0,0,0,colors); + + +} + +void proceduralFunction(Canvas& can) { + Background * bg = can.getBackground(); + // float x1[6] = { -275,-175,-200,-175,-275,-250 }; + // float y1[6] = { 275, 275, 225, 175, 175, 225 }; + // ConcavePolygon * c = new ConcavePolygon(0,0,0,6,x1,y1,0,0,0,RED); + // can.add(c); + + // Star * s = new Star(0,0,0,50,7,0,0,0,RED,false); + // can.add(s); + + // can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&c]() { + // c->changeXBy(10); + // }); + + bool flip = true; + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg, &flip]() { + if (flip) { + testSuite1(bg); + } else { + testSuite2(bg); + } + flip = !flip; + }); + + while (can.isOpen()) { + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.9*Canvas::getDisplayWidth(); + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Procedural Background", BLACK); + c.run(proceduralFunction); +} \ No newline at end of file diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile new file mode 100644 index 000000000..460fdd21d --- /dev/null +++ b/src/tests/testProgressBar/Makefile @@ -0,0 +1,87 @@ +# Makefile for testProgressBar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProgressBar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProgressBar.cpp b/src/tests/testProgressBar/testProgressBar.cpp similarity index 75% rename from src/tests/testProgressBar.cpp rename to src/tests/testProgressBar/testProgressBar.cpp index fc7e8bd98..787202afa 100644 --- a/src/tests/testProgressBar.cpp +++ b/src/tests/testProgressBar/testProgressBar.cpp @@ -29,18 +29,23 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void progressBarFunction(Canvas& can, int numThreads) { - const int X = 100, Y = X, W = can.getWindowWidth()-X*2, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; - ProgressBar pb(X,Y,W,H,MIN,MAX,SEGS); + Background * bg = can.getBackground(); + const int X = 0, Y = X, W = can.getWindowWidth()-200, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; + ProgressBar * pb = new ProgressBar(0,0,0,W,H,MIN,MAX,SEGS,0,0,0); int progress = 0; - for (int i = 0; i < SEGS; ++i) - can.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); + can.add(pb); + for (int i = 0; i < SEGS; ++i) { + float w = pb->getWidth(); + bg->drawText(pb->getCenterX() - w/2 + i*w/SEGS + 10, pb->getCenterY() + pb->getHeight()+8, 0, std::to_wstring(i), "./assets/freefont/FreeSerif.ttf", 36, 0,0,0, BLACK); + } while (can.isOpen()) { // Checks to see if the window has been closed can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class ++progress; for (int i = 0; i < SEGS; ++i) - pb.update(progress+i*(MAX/SEGS),i); - can.drawProgress(&pb); + pb->update(progress+i*(MAX/SEGS),i); + // pb->setPitch(can.getFrameNumber()); } + delete pb; } //Takes in the number of threads to use as a command line argument for the Canvas, defaulting to 8. diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile new file mode 100644 index 000000000..3380f3937 --- /dev/null +++ b/src/tests/testProjectiles/Makefile @@ -0,0 +1,87 @@ +# Makefile for Projectiles + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProjectiles + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProjectiles.cpp b/src/tests/testProjectiles/testProjectiles.cpp similarity index 79% rename from src/tests/testProjectiles.cpp rename to src/tests/testProjectiles/testProjectiles.cpp index 75ef3f439..6bd498542 100644 --- a/src/tests/testProjectiles.cpp +++ b/src/tests/testProjectiles/testProjectiles.cpp @@ -48,8 +48,9 @@ using namespace tsgl; */ void projectileFunction(Canvas& can) { const int WINDOW_W = can.getWindowWidth(); - int targetX = 0, targetY = WINDOW_W / 2, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion - int centerX = WINDOW_W / 2;// centerY = WINDOW_H / 2; //Center of screen + const int WINDOW_H = can.getWindowHeight(); + int centerX = 0, centerY = 0; //Center of screen + int targetX = -WINDOW_W/2, targetY = centerY, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion int numberOfTargets = 10; //Number of targets bool hit = false; //Determine if the target has been hit int score = 0; //Score @@ -64,22 +65,24 @@ void projectileFunction(Canvas& can) { }); //Create circles of target and add to Canvas - Circle * blueCircle = new Circle(targetX, targetY, 50, BLUE); //Outer circle - Circle * redCircle = new Circle(targetX, targetY, 30, RED); //Middle - Circle * yellowCircle = new Circle(targetX, targetY, 10, YELLOW); //Inner + Circle * blueCircle = new Circle(targetX,targetY,0, 50, 0,0,0, BLUE); //Outer circle + Circle * redCircle = new Circle(targetX,targetY,0, 30, 0,0,0, RED); //Middle + Circle * yellowCircle = new Circle(targetX,targetY,0, 10, 0,0,0, YELLOW); //Inner can.add(blueCircle); can.add(redCircle); can.add(yellowCircle); + + Background * bg = can.getBackground(); //Draw loop while(can.isOpen()) { can.sleep(); - can.clearProcedural(); + bg->clear(); targetX += coordinateChangerX; //Horizontal movement - targetY -= coordinateChangerY; //Vertical movement + targetY += coordinateChangerY; //Vertical movement if(hit) { //If we hit a target.... score++; - targetX = WINDOW_W + 60; + targetX = WINDOW_W / 2 + 60; hit = false; } if(targetX >= centerX) { //If it hits the middle of the screen, invert the vertical direction @@ -87,17 +90,17 @@ void projectileFunction(Canvas& can) { } if(targetX > WINDOW_W + 60) { //If the target is off the screen numberOfTargets--; //Decrement the number of targets left - targetX = 0; //Reset the target and inverter - targetY = 200; + targetX = -WINDOW_W / 2; //Reset the target and inverter + targetY = centerY; coordinateChangerY = 1; } if(numberOfTargets <= 5) { //Mix it up if there are only five targets left (speed up the targets) coordinateChangerX = 6; } //Move each circle to the target's location - blueCircle->setCenter(targetX, targetY); - redCircle->setCenter(targetX, targetY); - yellowCircle->setCenter(targetX, targetY); + blueCircle->setCenter(targetX, targetY,0); + redCircle->setCenter(targetX, targetY,0); + yellowCircle->setCenter(targetX, targetY,0); if(numberOfTargets == 0) { //End game std::cout << "Your score: " << score << std::endl; can.remove(redCircle); @@ -116,7 +119,6 @@ void projectileFunction(Canvas& can) { int main(int argc, char* argv[]) { int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Click the Target!"); //Can change the size of the window - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Click the Target!", BLACK); //Can change the size of the window c.run(projectileFunction); } diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile new file mode 100644 index 000000000..242b053c7 --- /dev/null +++ b/src/tests/testPyramid/Makefile @@ -0,0 +1,87 @@ +# Makefile for testPyramid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPyramid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPyramid/testPyramid.cpp b/src/tests/testPyramid/testPyramid.cpp new file mode 100644 index 000000000..fdbf30f6a --- /dev/null +++ b/src/tests/testPyramid/testPyramid.cpp @@ -0,0 +1,78 @@ +/* + * testPyramid.cpp + * + * Usage: ./testPyramid + */ + +#include +#include + +using namespace tsgl; + +void pyramidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(colors); + // printf("%f\n", testPyramid2->getAlpha()); + can.add(testPyramid); + can.add(testPyramid2); + can.add(testPyramid3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPyramid->setCenterX(sin(rotation)*200); + // testPyramid->setCenterY(cos(rotation)*200); + // testPyramid->setCenterZ(sin(rotation)*100); + // testPyramid->setYaw(rotation*45); + testPyramid->setPitch(rotation*45); + testPyramid2->setPitch(rotation*45); + testPyramid3->setPitch(rotation*45); + // testPyramid->setRoll(sin(rotation*45)*100+101); + // testPyramid->setHeight(sin(rotation)*100+101); + // testPyramid->setRadius(sin(rotation)*100+101); + // if(testPyramid->getHeight() >= 200) { + // delta = -5; + // } + // if(testPyramid->getHeight() <= 5) { + // delta = 5; + // } + // testPyramid->changeHeightBy(delta); + // if(testPyramid->getRadius() >= 200) { + // delta = -5; + // } + // if(testPyramid->getRadius() <= 5) { + // delta = 5; + // } + // testPyramid->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testPyramid->setColor(RED); + } else { + testPyramid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPyramid; + delete testPyramid2; + delete testPyramid3; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Basic Pyramid", BLACK); + c.run(pyramidFunction); +} \ No newline at end of file diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile new file mode 100644 index 000000000..00172d982 --- /dev/null +++ b/src/tests/testRectangle/Makefile @@ -0,0 +1,87 @@ +# Makefile for testRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRectangle/testRectangle.cpp b/src/tests/testRectangle/testRectangle.cpp new file mode 100644 index 000000000..c83e94fa6 --- /dev/null +++ b/src/tests/testRectangle/testRectangle.cpp @@ -0,0 +1,68 @@ +/* + * testRectangle.cpp + * + * Usage: ./testRectangle + */ + +#include +#include + +using namespace tsgl; + +void rectangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), + ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // rectangle->setCenterX(200); + // rectangle->setRotationPoint(0,0,0); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(colors); + // printf("%f\n", rectangle->getAlpha()); + can.add(rectangle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // rectangle->setCenterX(sin(floatVal/90)*100); + // rectangle->setCenterY(sin(floatVal/90)*100); + // rectangle->setCenterZ(sin(floatVal/90)*100); + // rectangle->setYaw(floatVal); + // rectangle->setPitch(floatVal); + // rectangle->setRoll(floatVal); + // rectangle->setWidth(sin(floatVal/90) *100 + 100); + // rectangle->setHeight(sin(floatVal/90) *100 + 200); + // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { + // delta *= -1; + // } + // rectangle->changeWidthBy(delta); + // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { + // delta *= -1; + // } + // rectangle->changeHeightBy(delta); + // if (delta > 0) { + // rectangle->setColor(colors); + // } else { + // rectangle->setColor(RED); + // } + floatVal += 1; + } + + delete rectangle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Rectangle", BLACK); + c.run(rectangleFunction); +} \ No newline at end of file diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile new file mode 100644 index 000000000..868937e75 --- /dev/null +++ b/src/tests/testRegularPolygon/Makefile @@ -0,0 +1,87 @@ +# Makefile for testRegularPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRegularPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRegularPolygon/testRegularPolygon.cpp b/src/tests/testRegularPolygon/testRegularPolygon.cpp new file mode 100644 index 000000000..9a4dd7ea9 --- /dev/null +++ b/src/tests/testRegularPolygon/testRegularPolygon.cpp @@ -0,0 +1,63 @@ +/* + * testRegularPolygon.cpp + * + * Usage: ./testRegularPolygon + */ + +#include +#include + +using namespace tsgl; + +void rpFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); + // rp->setCenterX(200); + // rp->setRotationPoint(0,0,0); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(colors); + // printf("%f\n", rp->getAlpha()); + can.add(rp); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // rp->setCenterX(sin(floatVal/90)*100); + // rp->setCenterY(sin(floatVal/90)*100); + // rp->setCenterZ(sin(floatVal/90)*100); + // rp->setYaw(floatVal); + // rp->setPitch(floatVal); + // rp->setRoll(floatVal); + // rp->setRadius(sin(floatVal/90)*100 + 300); + if (rp->getRadius() > 300 || rp->getRadius() < 100) { + delta *= -1; + } + rp->changeRadiusBy(delta); + if (delta > 0) { + rp->setColor(colors); + } else { + rp->setColor(RED); + } + floatVal += 1; + } + + delete rp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon", BLACK); + c.run(rpFunction); +} \ No newline at end of file diff --git a/src/tests/testRotation.cpp b/src/tests/testRotation.cpp deleted file mode 100644 index d2e309d93..000000000 --- a/src/tests/testRotation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - * testRotation.cpp tests various Drawable rotation functionalities. - */ -#include "tsgl.h" - -using namespace tsgl; - -void rotationFunction(Canvas& can) { - TextureHandler loader; - - Line * l = new Line(0,0,50,50, PURPLE); - l->setCenter(can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - Square * sq = new Square(50, 50, 50, BLUE); - sq->setCenter(can.getWindowWidth() / 2, 3 * can.getWindowHeight() / 4); - - Image * im = new Image("../assets/pics/test.png", loader, 0, 0, 50, 50); - im->setCenter(can.getWindowWidth() / 2, can.getWindowHeight() / 4); - - Text * text = new Text(L"dog", 100, 100, 32, GREEN); - text->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - Arrow * a = new Arrow(0,0,0,50,ORANGE, true); - a->setCenter(can.getWindowWidth() / 2, can.getWindowHeight()/2); - - // l->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - // sq->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - // im->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - l->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - im->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - text->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - sq->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - a->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - - can.add(sq); - can.add(im); - can.add(text); - can.add(l); - can.add(a); - - float rotation = 0; - while(can.isOpen()) { - sq->setRotation(rotation); - im->setRotation(rotation); - text->setRotation(rotation); - l->setRotation(rotation); - a->setRotation(rotation); - rotation += PI/365; - // sq->moveShapeBy(1,0); - // im->moveImageBy(1,0); - // text->moveTextBy(1,0); - // l->moveShapeBy(1,0); - can.sleepFor(.02); - } - - delete l; - delete sq; - delete im; - delete text; - delete a; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1000; - int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Rotation"); //Can change the size of the window - c.run(rotationFunction); -} \ No newline at end of file diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile new file mode 100644 index 000000000..ad1fa2ebf --- /dev/null +++ b/src/tests/testScreenshot/Makefile @@ -0,0 +1,87 @@ +# Makefile for testScreenshot + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testScreenshot + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testScreenshot.cpp b/src/tests/testScreenshot/testScreenshot.cpp similarity index 71% rename from src/tests/testScreenshot.cpp rename to src/tests/testScreenshot/testScreenshot.cpp index 96ce86a03..f3b751956 100644 --- a/src/tests/testScreenshot.cpp +++ b/src/tests/testScreenshot/testScreenshot.cpp @@ -27,7 +27,8 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void screenShotFunction(Cart& can) { - int xNew = can.getWindowWidth() / 2, yNew = can.getWindowHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; + Background * bg = can.getBackground(); + int xNew = can.getCartWidth() / 2, yNew = can.getCartHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; can.recordForNumFrames(FPS * 30); while (can.isOpen()) { // Checks to see if the window has been closed can.sleep(); @@ -35,20 +36,14 @@ void screenShotFunction(Cart& can) { yOld = yMid; xMid = xNew; yMid = yNew; - xNew = rand() % can.getWindowWidth(); - yNew = rand() % can.getWindowHeight(); - can.drawTriangle(xOld, yOld, xMid, yMid, xNew, yNew, Colors::randomColor(), true); + xNew = saferand(0, can.getCartWidth()); + yNew = saferand(0, can.getCartHeight()); + bg->drawTriangle(xOld,yOld,0, xMid,yMid,0, xNew, yNew,0, 0,0,0, Colors::randomColor()); } } //Takes command-line arguments for the width and height of the screen int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 800; //Width and height - int h = (argc > 2) ? atoi(argv[2]) : 600; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 800; - h = 600; - } - Cart c(-1, -1, w, h, 0, 0, 800, 600,"Screenshot Test"); + Cart c(-1, -1, 800, 600, 0, 0, 800, 600,"Screenshot Test"); c.run(screenShotFunction); } diff --git a/src/tests/testSmartSort.cpp b/src/tests/testSmartSort.cpp deleted file mode 100644 index f38740953..000000000 --- a/src/tests/testSmartSort.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * testSmartSort.cpp - * - * Usage: ./testSmartSort - */ - -#include -#include - -using namespace tsgl; - -const int MARGIN = 8; // Border for drawing - -enum MergeState { - S_MERGE = 1, - S_SHIFT = 2, - S_WAIT = 3, - S_DONE = 4, - S_HIDE = 5 -}; - -struct sortData { - ColorFloat color; //Color of the thread - MergeState state; //Current state of the threads - int first, last, //Start and end of our block - left, right, //Indices of two numbers to compare - fi, hi, li, //Indices of first middle and last numbers in a set - depth; //Current depth of the merge - int* a; //Array of numbers to sort - int seg, segs; //Current / total segments - int size; - - sortData(int* arr, int f, int l, ColorFloat c) { - fi = hi = li = 0; //Initialize indices - left = right = 0; //Initialize bounds - color = c; //Set the color - a = arr; //Get a pointer to the array we'll be sorting - first = f; //Set the first element we need to worry about - last = l; //Set the last element we need to worry about - depth = 0; //We start at depth 0 - seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment - while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done - ++depth; //Otherwise, increment the depth... - segs *= 2; //...and double the number of segments - } - state = S_SHIFT; //Start Merging - size = 2; - } - - void restart(int l) { - depth = 0; - hi = last; - right = hi+1; - last = li = l; - fi = left = first; - state = S_MERGE; - size *= 2; - } - - void sortStep() { - int tmp, pivot, jump; - switch(state) { - case S_SHIFT: - pivot = jump = segs/2; - fi = first; li = last; - hi = (fi + li) / 2; //Set our half index to the median of our first and last - for (tmp = depth; tmp > 0; --tmp) { - jump /= 2; - if (seg < pivot) { - pivot -= jump; - li = hi; //Set out last index to our old half index - } else { - pivot += jump; - fi = hi+1; //Set out first index to our old half index plus one - } - hi = (fi + li) / 2; //Set our new half index to the median of our first and last - } - left = fi; right = hi+1; - state = S_MERGE; //We're ready to start Merging - break; - case S_MERGE: - if (left > right || right > last) { - seg = 0; //Reset our segment(s) - segs /= 2; //We're now using half as many segments - state = (depth-- == 0) ? S_WAIT : S_SHIFT; - } else if (right > li) { - ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices - } else if (left <= hi && a[left] < a[right]) { - ++left; - } else { - tmp = a[right]; - for (int x = right; x > left; --x) - a[x] = a[x-1]; - a[left] = tmp; - ++left; ++right; ++hi; - } - break; - default: - break; - } - } -}; - -/*! - * \brief Visualization of the bottom-up mergesort algorithm. - * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. - * \details Uses lines to represent the items being sorted. - * \details At the start, the items being sorted are all divided. - * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. - * \details Different colors represent different sections being sorted. - * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. - */ -void smartSortFunction(Canvas& can, int threads, int size) { - const int IPF = 1; // Iterations per frame - int* numbers = new int[size]; // Array to store the data - for (int i = 0; i < size; i++) - numbers[i] = rand() % (can.getWindowHeight() - MARGIN); - - int bs = size / threads; - int ex = size % threads; - sortData** sd = new sortData*[threads]; - int f = 0; - int l = (ex == 0) ? bs-1 : bs; - for (int i = 0; i < threads; ++i) { - sd[i] = new sortData(numbers,f,l,Colors::highContrastColor(i)); - f = l+1; - if (i < ex-1) l += (bs + 1); - else l += bs; - } - while (can.isOpen()) { - #pragma omp parallel num_threads(threads) - { - int tid = omp_get_thread_num(); - can.sleep(); - if (sd[tid]->state == S_WAIT) { //Merge waiting threads - if ((tid % sd[tid]->size) > 0) - sd[tid]->state = S_DONE; - else { - int next = tid+sd[tid]->size/2; - if (next < threads && sd[next]->state == S_DONE) { - sd[next]->state = S_HIDE; - sd[tid]->restart(sd[next]->last); - } - } - } - for (int i = 0; i < IPF; i++) - sd[tid]->sortStep(); - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - int start = MARGIN/2 + sd[tid]->first, height; - int cwh = can.getWindowHeight() - MARGIN/2; - ColorFloat color; - if (sd[tid]->state != S_HIDE) { - //Draw a black rectangle over our portion of the screen to cover up the old drawing - can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); - for (int i = sd[tid]->first; i < sd[tid]->last; ++i, ++start) { - height = numbers[i]; - if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) - color = WHITE; - else { - if (i == sd[tid]->right || i == sd[tid]->left) - color = WHITE; - else if (i < sd[tid]->left) - color = sd[tid]->color; - else if (i >= sd[tid]->fi && i <= sd[tid]->li) - color = Colors::blend(sd[tid]->color, WHITE, 0.5f); - else - color = Colors::blend(sd[tid]->color, BLACK, 0.5f); - } - can.drawLine(start, cwh - height, start, cwh, color); - } - } - can.resumeDrawing(); //Tell the Canvas it can resume updating - } - } - for (int i = 0; i < threads; ++i) - delete sd[i]; - delete [] sd; - delete [] numbers; -} - -//Takes in command line arguments for the window width and height -//as well as for the number of threads to use -int main(int argc, char* argv[]) { - int s = (argc > 1) ? atoi(argv[1]) : 1024; - if (s < 10) s = 10; - int w = s + MARGIN; - int h = w/2; - - int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); - for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 - - Canvas c(-1, -1, w, h, "Bottom-up Merge Sort"); - c.setBackgroundColor(BLACK); - c.run(smartSortFunction, threads, s); -} diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile new file mode 100644 index 000000000..993a84aa2 --- /dev/null +++ b/src/tests/testSpectrogram/Makefile @@ -0,0 +1,87 @@ +# Makefile for testSpectrogram + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrogram + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrogram.cpp b/src/tests/testSpectrogram/testSpectrogram.cpp similarity index 83% rename from src/tests/testSpectrogram.cpp rename to src/tests/testSpectrogram/testSpectrogram.cpp index 99eb133ae..1de9fc85f 100644 --- a/src/tests/testSpectrogram.cpp +++ b/src/tests/testSpectrogram/testSpectrogram.cpp @@ -40,8 +40,9 @@ using namespace tsgl; * \param fname The name of the file to get the image from. */ void spectrogramFunction(Canvas& can, std::string fname) { + Background * bg = can.getBackground(); const int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - can.drawImage(fname, 0, 0, cww, cwh); + bg->drawImage(0,0,0,fname,cww, cwh,0,0,0); Spectrogram sp(VERTICAL,500); can.sleepFor(0.1f); // can.recordForNumFrames(FPS); @@ -50,19 +51,19 @@ void spectrogramFunction(Canvas& can, std::string fname) { { int tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); int blockSize = cwh / nthreads; - int start = tid * blockSize; - int end = (tid == (nthreads-1)) ? cwh : (tid+1) * blockSize; + int start = tid * blockSize - cwh / 2; + int end = (tid == (nthreads-1)) ? cwh / 2 : start + blockSize; for (int j = start; j < end; ++j) { if (can.isOpen()) { can.sleep(); ColorHSV hsv; - for (int i = 0; i < cww; ++i) { - hsv = can.getPoint(i,j); + for (int i = -cww/2; i < cww/2; ++i) { + hsv = bg->getPixel(i,j); if (hsv.H == hsv.H) { //Check for NAN sp.updateLocked(MAX_COLOR*hsv.H/6,1.0f,0.8f); sp.updateCritical(MAX_COLOR*hsv.H/6,1.0f,0.8f); } - can.drawPoint(i,j,ColorHSV(0.0f,0.0f,hsv.V)); + bg->drawPixel(i,j,ColorHSV(0.0f,0.0f,hsv.V)); } #pragma omp atomic ++numChecked; @@ -71,15 +72,16 @@ void spectrogramFunction(Canvas& can, std::string fname) { } } // can.sleepFor(FRAME); - can.drawImage(fname, 0, 0, cww, cwh); + bg->drawImage(0,0,0,fname,cww, cwh,0,0,0); sp.finish(); + can.wait(); } //Takes command-line arguments for the file name of the picture to use in the spectrogram function int main(int argc, char* argv[]) { - std::string fname = argc > 1 ? argv[1] : "../assets/pics/colorful_cars.jpg"; + std::string fname = argc > 1 ? argv[1] : "./assets/pics/colorful_cars.jpg"; int w, h; - TextureHandler::getDimensions(fname,w,h); + Image::getFileResolution(fname,w,h); Canvas c(-1, Canvas::getDisplayHeight()-h, w, h ,"Spectrogram"); c.run(spectrogramFunction, fname); } diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile new file mode 100644 index 000000000..4faf57b31 --- /dev/null +++ b/src/tests/testSpectrum/Makefile @@ -0,0 +1,87 @@ +# Makefile for testSpectrum + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrum + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrum.cpp b/src/tests/testSpectrum/testSpectrum.cpp similarity index 86% rename from src/tests/testSpectrum.cpp rename to src/tests/testSpectrum/testSpectrum.cpp index 63fb5f125..ec613f350 100644 --- a/src/tests/testSpectrum.cpp +++ b/src/tests/testSpectrum/testSpectrum.cpp @@ -32,6 +32,7 @@ using namespace tsgl; * \param numberOfThreads Reference to the number of threads to use. */ void spectrumFunction(Canvas& can, int numberOfThreads) { + Background * bg = can.getBackground(); #pragma omp parallel num_threads(omp_get_num_procs()) { int holder = omp_get_num_threads(); //Temp variable @@ -45,9 +46,9 @@ void spectrumFunction(Canvas& can, int numberOfThreads) { } while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = omp_get_thread_num(); i < NUM_COLORS; i += nthreads) - for (int j = 0; j < NUM_COLORS; j++) - can.drawPoint(i, j, ColorInt(i, j, can.getReps() % NUM_COLORS)); + for (int i = -NUM_COLORS/2 + omp_get_thread_num(); i < NUM_COLORS/2; i += nthreads) + for (int j = -NUM_COLORS/2; j < NUM_COLORS/2; j++) + bg->drawPixel(i, j, ColorInt(i + NUM_COLORS/2, j + NUM_COLORS/2, can.getReps() % NUM_COLORS)); } } } @@ -55,7 +56,7 @@ void spectrumFunction(Canvas& can, int numberOfThreads) { //Takes command-line arguments for the number of threads to use int main(int argc, char* argv[]) { int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); //Number of threads to use - Canvas c(-1,-1,255,255,"The Color Spectrum"); + Canvas c(-1,-1,256,256,"The Color Spectrum"); c.run(spectrumFunction, t); } diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile new file mode 100644 index 000000000..0ca6836de --- /dev/null +++ b/src/tests/testSphere/Makefile @@ -0,0 +1,87 @@ +# Makefile for testSphere + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSphere + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSphere/testSphere.cpp b/src/tests/testSphere/testSphere.cpp new file mode 100644 index 000000000..3d602168a --- /dev/null +++ b/src/tests/testSphere/testSphere.cpp @@ -0,0 +1,80 @@ +/* + * testSphere.cpp + * + * Usage: ./testSphere + */ + +#include +#include + +using namespace tsgl; + +void sphereFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); + Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); + testSphere->setIsOutlined(true); + testSphere2->setIsOutlined(true); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(colors); + // printf("%f\n", testSphere->getAlpha()); + can.add(testSphere); + can.add(testSphere2); + float rotation = 0.0f; + // GLfloat delta = 5; + bool boolean = true; + while (can.isOpen()) { + can.sleep(); + // testSphere->setCenterX(sin(rotation) * 100); + // testSphere->setCenterY(cos(rotation) * 100); + // testSphere->setCenterZ(sin(rotation) * 100); + // testSphere->setYaw(rotation*45); + // testSphere->setPitch(rotation*45); + testSphere->setRoll(rotation*45); + // testSphere->setRadius(cos(rotation) * 100 +101); + // if(testSphere->getRadius() >= 200) { + // delta = -5; + // } + // if(testSphere->getRadius() <= 500) { + // delta = 5; + // } + // testSphere->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + // printf("%f\n", rotation*45); + if (rotation*45 >= 360) { + if (boolean) { + testSphere->setColor(RED); + } else { + testSphere->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + + rotation+=0.01; + } + + delete testSphere; + delete testSphere2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Sphere", BLACK); + c.run(sphereFunction); +} \ No newline at end of file diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile new file mode 100644 index 000000000..b23802512 --- /dev/null +++ b/src/tests/testSquare/Makefile @@ -0,0 +1,87 @@ +# Makefile for testSquare + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSquare + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSquare/testSquare.cpp b/src/tests/testSquare/testSquare.cpp new file mode 100644 index 000000000..56eaf740a --- /dev/null +++ b/src/tests/testSquare/testSquare.cpp @@ -0,0 +1,66 @@ +/* + * testSquare.cpp + * + * Usage: ./testSquare + */ + +#include +#include + +using namespace tsgl; + +void squareFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Square * square = new Square(0,0,0,200,0,0,0,colors); + Square * square2 = new Square(-250,0,0,200,0,0,0,RED); + // square->setCenterX(200); + // square->setRotationPoint(0,0,0); + can.add(square); + can.add(square2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + bool ss = false; + while (can.isOpen()) { + can.sleep(); + // square->setCenterX(sin(floatVal/90) * 100); + // square->setCenterY(sin(floatVal/90) * 100); + // square->setCenterZ(sin(floatVal/90) * 100); + // square->setYaw(floatVal); + // square->setPitch(floatVal); + // square->setRoll(floatVal); + // square->setSideLength(sin(floatVal/90) * 100 + 300); + // if (square->getSideLength() > 300 || square->getSideLength() < 100) { + // delta *= -1; + // } + // square->changeSideLengthBy(delta); + // if (delta > 0) { + // square->setColor(colors); + // } else { + // square->setColor(RED); + // } + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + floatVal += 1; + } + + delete square; + delete square2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Square", BLACK); + c.run(squareFunction); +} \ No newline at end of file diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp deleted file mode 100644 index 561ef0989..000000000 --- a/src/tests/testStar.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * testStar.cpp tests displaying the Star class - */ -#include -using namespace tsgl; - -int main() { - Canvas c(-1, -1, 1000, 1000, "Stars", FRAME * 13); - c.start(); - - int xs[4] = {250, 250, 750, 750}; - int ys[4] = {250, 750, 250, 750}; - - ColorFloat * colors = new ColorFloat[16]; - colors[0] = YELLOW; - for(int i = 1; i < 16; i ++) { - colors[i] = GREEN; - } - - float rotation = 0; - Star * s1 = new Star(xs[2], ys[2], 125, 8, colors, colors, true); - Star * s2 = new Star(xs[3], ys[3], 75, 9, PURPLE, BLUE, false); - Star * s3 = new Star(xs[0], ys[0], 100, 6, RED, true, true); - Star * s4 = new Star(xs[1], ys[1], 50, 7, BLUE, false, false); - c.add(s1); - c.add(s2); - c.add(s3); - c.add(s4); - - while( c.isOpen() ) { - c.sleep(); - c.pauseDrawing(); - rotation += PI / 3; - s1->setRotation(rotation); - c.resumeDrawing(); - c.sleepFor(1); - } - - c.wait(); - - delete[] colors; - delete s1; - delete s2; - delete s3; - delete s4; - return 0; -} \ No newline at end of file diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile new file mode 100644 index 000000000..027f2220a --- /dev/null +++ b/src/tests/testStar/Makefile @@ -0,0 +1,87 @@ +# Makefile for testStar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testStar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testStar/testStar.cpp b/src/tests/testStar/testStar.cpp new file mode 100644 index 000000000..68eaa01a8 --- /dev/null +++ b/src/tests/testStar/testStar.cpp @@ -0,0 +1,52 @@ +/** + * testStar.cpp tests displaying the Star class + * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. + */ +#include +using namespace tsgl; + +void starFunction(Canvas& c) { + ColorFloat * colors = new ColorFloat[400]; + colors[0] = ColorFloat(1,0,0,1); + for(int i = 1; i < 10; i ++) { + // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); + colors[i] = ColorFloat(0,0,1,1); + } + + Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); + // s1->setColor(RED); + c.add(s1); + + float floatVal = 0.0f; + GLfloat delta = 5; + while (c.isOpen()) { + c.sleep(); + // s1->setCenterX(sin(floatVal/90) * 100); + // s1->setCenterY(sin(floatVal/90) * 100); + // s1->setCenterZ(sin(floatVal/90) * 100); + // s1->setYaw(floatVal); + // s1->setPitch(floatVal); + // s1->setRoll(floatVal); + // s1->setRadius(sin(floatVal/90) * 100 + 300); + if (s1->getRadius() > 300 || s1->getRadius() < 100) { + delta *= -1; + } + s1->changeRadiusBy(delta); + if (delta > 0) { + s1->setColor(colors); + } else { + s1->setColor(RED); + } + floatVal += 1; + } + + delete[] colors; + // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. +} + +int main(int argc, char* argv[]) { + int w = 700; + int h = 700; + Canvas c(-1, -1, w, h, "Stars"); + c.run(starFunction); +} \ No newline at end of file diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp deleted file mode 100644 index 0ff6fe6ec..000000000 --- a/src/tests/testText.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * testText.cpp - * - * Usage: ./testSpectrum - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a Canvas. - * \details - * - We declare some colors to use for drawing. - * - We changed it so that now a default text font is loaded if one is not specified. - * - We draw a few lines of text in various colors using drawText(). - * . - * \param can Reference to the Canvas being drawn to. - * \param font The font of the text. - */ -void textFunction(Canvas& can, std::string font) { - ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); - ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); - ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); - - can.setFont(font); - can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - can.drawText("Something extraordinary happened.", 16, 150, 32, RED); - can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - 32, BLUE); - can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * text = new Text(L"Blergh", 0,0, 30, PURPLE); - text->setFont(font); - text->setCenter(can.getWindowWidth()/2, 4*can.getWindowHeight() /5); - text->setRotation(PI/8); - can.add(text); - while(can.isOpen()) { - can.sleep(); - } - delete text; - -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; - std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "Text on a Canvas"); - c.run(textFunction, font); -} diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile new file mode 100644 index 000000000..5113a495c --- /dev/null +++ b/src/tests/testText/Makefile @@ -0,0 +1,87 @@ +# Makefile for testText + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testText + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testText/testText.cpp b/src/tests/testText/testText.cpp new file mode 100644 index 000000000..dbb4ec0dd --- /dev/null +++ b/src/tests/testText/testText.cpp @@ -0,0 +1,78 @@ +/* + * testText.cpp + * + * Usage: ./testSpectrum + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a Canvas. + * \details + * - We changed it so that now a default text font is loaded if one is not specified. + * - We draw a few lines of text in various colors using drawText(). + * . + * \param can Reference to the Canvas being drawn to. + * \param font The font of the text. + */ +void textFunction(Canvas& can, std::string font) { + // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); + // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + // 32, BLUE); + // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); + Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); + can.add(lowercase); + Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); + can.add(uppercase); + Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); + // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); + can.add(random); + // can.add(rec); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { + random->setText(L"Glorgaborg"); + // random->setColor(RED); + // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); + // random->setSize(100); + }); + + bool ss = false; + float rotation = 0.0f; + while(can.isOpen()) { + can.sleep(); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // random->setCenterX(sin(rotation)*200); + // random->setCenterY(cos(rotation)*200); + // random->setCenterZ(sin(rotation)*100); + // random->setYaw(rotation*45); + random->setPitch(rotation*45); + // random->setRoll(rotation*45); + rotation+=0.01; + } + delete lowercase; + delete uppercase; + delete random; + +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; + std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 1.2f*Canvas::getDisplayHeight(); + h = 0.75f*w; + } + Canvas c(-1, -1, w, h, "Text on a Canvas"); + c.run(textFunction, font); +} diff --git a/src/tests/testTextCart.cpp b/src/tests/testTextCart.cpp deleted file mode 100644 index 77f5956a7..000000000 --- a/src/tests/testTextCart.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextCart.cpp - * - * Usage: ./testTextCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a CartesianCanvas. - * \details Same as textFunction, but with a CartesianCanvas and black text. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - * \param font The font of the text. - */ -void textCartFunction(Cart& can, std::string font) { - can.setFont(font); - can.drawText(L"A long time ago, in a galaxy far, far away.", 1, 2, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 1, 1.9, 32, BLACK); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 1, 1.8, 32, BLACK); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 1, 1.7, - 32, BLACK); - can.drawText(L"Of *what* exactly that extraordinary event was.", 1, 1.6, 32, BLACK); - can.drawText(L"And to that I say...oh well.", 1, 1.5, 32, BLACK); -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font file for the text -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w - 200.0f; - std::string font = argv[3]; //Font - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.75 * w; - } - Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); - c.run(textCartFunction, font); -} diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile new file mode 100644 index 000000000..889781ecb --- /dev/null +++ b/src/tests/testTextCart/Makefile @@ -0,0 +1,87 @@ +# Makefile for testTextCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextCart/testTextCart.cpp b/src/tests/testTextCart/testTextCart.cpp new file mode 100644 index 000000000..1987729fe --- /dev/null +++ b/src/tests/testTextCart/testTextCart.cpp @@ -0,0 +1,43 @@ +/* + * testTextCart.cpp + * + * Usage: ./testTextCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a CartesianCanvas. + * \details Same as textFunction, but with a CartesianCanvas and black text. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + * \param font The font of the text. + */ +void textCartFunction(Cart& can, std::string font) { + CartesianBackground * cart = can.getBackground(); + float w = can.getCartWidth(); + float h = can.getCartHeight(); + // Text * t = new Text(w/2, h/2, 0, L"1.5\u03C0", font, (float) 1/7, 0,0,0, BLACK); + // can.add(t); + cart->drawText(w/2, h * 11/12, 0, L"A long time ago, in a galaxy far, far away.", font, (float) 3/14, 0,0,0, BLACK); + cart->drawText(w/2, h * 9/12, 0, L"Something extraordinary happened.", font, (float) 3/14, 0,0,0, BLACK); + cart->drawText(w/2, h * 7/12, 0, L"Something far more extraordinary than anything mankind has ever seen.", font, (float) 3/14, 0,0,0, BLACK); + cart->drawText(w/2, h * 5/12, 0, L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", font, (float) 3/14, 0,0,0, BLACK); + cart->drawText(w/2, h * 3/12, 0, L"Of *what* exactly that extraordinary event was.", font, (float) 3/14, 0,0,0, BLACK); + cart->drawText(w/2, h * 1/12, 0, L"And to that I say...oh well.", font, (float) 3/14, 0,0,0, BLACK); + while(can.isOpen()) { + can.sleep(); + } +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font file for the text +int main(int argc, char * argv[]) { + //Width and height + int w = 960; + int h = 420; + std::string font = "./assets/freefont/FreeSerif.ttf";// argv[3]; //Font + Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); + c.run(textCartFunction, font); +} diff --git a/src/tests/testTextTwo.cpp b/src/tests/testTextTwo.cpp deleted file mode 100644 index b6ef8060e..000000000 --- a/src/tests/testTextTwo.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextTwo.cpp - * - * Usage: ./testTextTwo - */ - -#include - -using namespace tsgl; - -/** - * \brief Tests to see if text is still drawn if a font is not specified. - * \details Same as textFunction, but with the setFont line deleted. - * \param can Reference to the Canvas being drawn to. - */ -void textFunctionTwo(Canvas& can) { - ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); - ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); - ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); - - can.drawText(L"A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 16, 150, 32, RED); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - 32, BLUE); - can.drawText(L"Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - can.drawText(L"And to that I say...oh well.", 16, 550, 32, WHITE); -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 300.0f; - if(w <= 0 || h <= 0) { //Check the validity of the width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "More Text on a Canvas"); - c.run(textFunctionTwo); -} diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile new file mode 100644 index 000000000..d603aeaa9 --- /dev/null +++ b/src/tests/testTextTwo/Makefile @@ -0,0 +1,87 @@ +# Makefile for testTextTwo + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextTwo + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextTwo/testTextTwo.cpp b/src/tests/testTextTwo/testTextTwo.cpp new file mode 100644 index 000000000..b82c83ba0 --- /dev/null +++ b/src/tests/testTextTwo/testTextTwo.cpp @@ -0,0 +1,35 @@ +/* + * testTextTwo.cpp + * + * Usage: ./testTextTwo + */ + +#include + +using namespace tsgl; + +/** + * \brief Tests to see if text is still drawn if a font is not specified. + * \details Same as textFunction, but with the setFont line deleted. + * \param can Reference to the Canvas being drawn to. + */ +void textFunctionTwo(Canvas& can) { + Background * bg = can.getBackground(); + float WW = can.getWindowWidth() / 2; float WH = can.getWindowHeight() / 2; + std::string font = "./assets/freefont/FreeSerif.ttf"; + bg->drawText(0, WH * 5/6, 0, L"A long time ago, in a galaxy far, far away.", font, 30, 0,0,0, BLACK); + bg->drawText(0, WH * 3/6, 0, L"Something extraordinary happened.", font, 30, 0,0,0, RED); + bg->drawText(0, WH * 1/6, 0,L"Something far more extraordinary than anything mankind has ever seen.", font, 30, 0,0,0, GREEN); + bg->drawText(0,-WH * 1/6, 0,L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", font, 30, 0,0,0, BLUE); + bg->drawText(0,-WH * 3/6, 0,L"Of *what* exactly that extraordinary event was.", font, 30, 0,0,0, PURPLE); + bg->drawText(0,-WH * 5/6, 0,L"And to that I say...oh well.", font, 30, 0,0,0, WHITE); +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + //Width and height + int w = 960; + int h = 420; + Canvas c(-1, -1, w, h, "More Text on a Canvas"); + c.run(textFunctionTwo); +} diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile new file mode 100644 index 000000000..b5c070f2b --- /dev/null +++ b/src/tests/testTransparency/Makefile @@ -0,0 +1,87 @@ +# Makefile for testTransparency + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTransparency + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTransparency/testTransparency.cpp b/src/tests/testTransparency/testTransparency.cpp new file mode 100644 index 000000000..efb7867d3 --- /dev/null +++ b/src/tests/testTransparency/testTransparency.cpp @@ -0,0 +1,31 @@ +/* + * testTransparency.cpp + * + * Usage: ./testTransparency + */ + +#include +#include + +using namespace tsgl; + +void transparencyFunction(Canvas& can) { + Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); + Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); + Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); + can.add(cube2); + can.add(cube); + can.add(rec); + + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + cube2->setCenterZ(150 * cos(rotation)); + rotation += 0.1; + } +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Transparency", BLACK); + c.run(transparencyFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile new file mode 100644 index 000000000..f6a42058c --- /dev/null +++ b/src/tests/testTriangle/Makefile @@ -0,0 +1,87 @@ +# Makefile for testTriangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangle/testTriangle.cpp b/src/tests/testTriangle/testTriangle.cpp new file mode 100644 index 000000000..f29e650cb --- /dev/null +++ b/src/tests/testTriangle/testTriangle.cpp @@ -0,0 +1,59 @@ +/* + * testTriangle.cpp + * + * Usage: ./testTriangle + */ + +#include +#include + +using namespace tsgl; + +void triangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); + Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); + // triangle->setCenterX(200); + // triangle->setRotationPoint(0,0,0); + can.add(triangle); + can.add(triangle2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // triangle->setCenterX(sin(floatVal/90) * 100); + // triangle->setCenterY(sin(floatVal/90) * 100); + // triangle->setCenterZ(sin(floatVal/90) * 100); + // triangle->setYaw(floatVal); + // triangle->setPitch(floatVal); + // triangle->setRoll(floatVal); + if (floatVal < 200) { + triangle->setColor(colors); + } else { + triangle->setColor(RED); + if (floatVal > 400) { + floatVal = 0; + } + } + floatVal += 1; + } + + delete triangle; + delete triangle2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Triangle", BLACK); + c.run(triangleFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile new file mode 100644 index 000000000..741365485 --- /dev/null +++ b/src/tests/testTriangleStrip/Makefile @@ -0,0 +1,87 @@ +# Makefile for testTriangleStrip + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangleStrip + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangleStrip/testTriangleStrip.cpp b/src/tests/testTriangleStrip/testTriangleStrip.cpp new file mode 100644 index 000000000..dc281cd33 --- /dev/null +++ b/src/tests/testTriangleStrip/testTriangleStrip.cpp @@ -0,0 +1,60 @@ +/* + * testTriangleStrip.cpp + * + * Usage: ./testTriangleStrip + */ + +#include +#include + +using namespace tsgl; + +void triangleStripFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { 0,-50,50,-50,50,0 }; + float y[] = { -100,-50,-50,50,50,100 }; + float z[] = { 0,50,50,50,50,0 }; + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); + // ts->setIsOutlined(true); + // ts->setCenterX(2); + ts->setRotationPoint(0,0,0); + can.add(ts); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // ts->setCenterX(sin(floatVal/90) * 100); + // ts->setCenterY(sin(floatVal/90) * 100); + // ts->setCenterZ(sin(floatVal/90) * 100); + // ts->setYaw(floatVal); + ts->setPitch(floatVal); + // ts->setRoll(floatVal); + // if (floatVal < 200) { + // ts->setColor(colors); + // } else { + // ts->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete ts; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip", BLACK); + c.run(triangleStripFunction); +} \ No newline at end of file diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile new file mode 100644 index 000000000..fc5fde6e4 --- /dev/null +++ b/src/tests/testUnits/Makefile @@ -0,0 +1,87 @@ +# Makefile for testUnits + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testUnits + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS := -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS := -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testUnits.cpp b/src/tests/testUnits/testUnits.cpp similarity index 93% rename from src/tests/testUnits.cpp rename to src/tests/testUnits/testUnits.cpp index f62a3271a..12aff037c 100644 --- a/src/tests/testUnits.cpp +++ b/src/tests/testUnits/testUnits.cpp @@ -18,7 +18,7 @@ int main() { //Begin Unit testing std::cout << "Begin unit testing...." << std::endl << std::endl; Canvas::runTests(); // Canvas (Image test included) - TextureHandler::runTests(); // TextureHandler + // TextureHandler::runTests(); // TextureHandler ConcavePolygon::runTests(); // ConcavePolygon ConvexPolygon::runTests(); // ConvexPolygon CartesianCanvas::runTests(); // CartesianCanvas diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile new file mode 100644 index 000000000..8725ae49b --- /dev/null +++ b/src/tests/test_specs/Makefile @@ -0,0 +1,86 @@ +# Makefile for test_specs + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test_specs + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test_specs.cpp b/src/tests/test_specs/test_specs.cpp similarity index 96% rename from src/tests/test_specs.cpp rename to src/tests/test_specs/test_specs.cpp index 367badcb1..c11fa8271 100644 --- a/src/tests/test_specs.cpp +++ b/src/tests/test_specs/test_specs.cpp @@ -1,4 +1,6 @@ -#include "tsgl.h" +#include + +using namespace tsgl; int main(int argc, char* argv[]) { glfwInit(); diff --git a/uninstall-cygwin b/uninstall-cygwin new file mode 100644 index 000000000..bc8a7d692 --- /dev/null +++ b/uninstall-cygwin @@ -0,0 +1,16 @@ +#!/bin/sh + +#make clean +make clean + +#Take out the lib and bin folders +rm -rf bin lib + +#Take out the TSGL lib.a and lib.so files +rm /usr/local/lib/libtsgl.* + +#Take out the TSGL folder containing the .h files +rm -rf /usr/local/include/TSGL + +#Done. +echo "\n Uninstall complete!\n" diff --git a/uninstall-mac b/uninstall-mac index e540fbd49..288e682b9 100755 --- a/uninstall-mac +++ b/uninstall-mac @@ -7,8 +7,11 @@ make clean #Remove the bin and lib folders rm -rf bin lib +#Remove the copy of stb from /usr/local/include +sudo rm -rf /usr/local/include/stb + #Take out the TSGL header files -rm -rf /usr/local/include/TSGL +sudo rm -rf /usr/local/include/TSGL #Take out the TSGL lib files rm /usr/local/lib/libtsgl.*