Merge branch 'master' of http://git.j3d1.de/KKK/KlassischeKeplerKriege
This commit is contained in:
commit
756e98fe9f
55 changed files with 123227 additions and 437 deletions
|
@ -8,7 +8,7 @@ function(setup_target NAME)
|
||||||
set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||||
target_compile_options(${NAME} PRIVATE -Wall -Wextra)
|
target_compile_options(${NAME} PRIVATE -Wall -Wextra)
|
||||||
target_compile_options(${NAME} PRIVATE -fdiagnostics-color=always)
|
target_compile_options(${NAME} PRIVATE -fdiagnostics-color=always)
|
||||||
target_compile_options(${NAME} PRIVATE $<$<CONFIG:DEBUG>:-ggdb -O2>)
|
target_compile_options(${NAME} PRIVATE $<$<CONFIG:DEBUG>:-ggdb -O0>)
|
||||||
target_compile_options(${NAME} PRIVATE $<$<CONFIG:RELEASE>:-O3 -NDEBUG>)
|
target_compile_options(${NAME} PRIVATE $<$<CONFIG:RELEASE>:-O3 -NDEBUG>)
|
||||||
endfunction(setup_target)
|
endfunction(setup_target)
|
||||||
|
|
||||||
|
|
BIN
data/img/planet_mars.png
Normal file
BIN
data/img/planet_mars.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
data/img/test.png
Normal file
BIN
data/img/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
114662
data/mesh/planet_128.stl
Normal file
114662
data/mesh/planet_128.stl
Normal file
File diff suppressed because it is too large
Load diff
18
data/mesh/rocket.scad
Normal file
18
data/mesh/rocket.scad
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
$fn = 16;
|
||||||
|
|
||||||
|
translate([0, 0, -0.2]) {
|
||||||
|
cylinder(r=0.05, h=0.4);
|
||||||
|
translate([0, 0, 0.25]) cylinder(r=0.065, h=0.1);
|
||||||
|
translate([0, 0, 0.35]) sphere(r=0.07);
|
||||||
|
translate([0, 0, 0.35]) cylinder(r=0.01, h=0.2);
|
||||||
|
|
||||||
|
for (h=[0.07, 0.2]) {
|
||||||
|
translate([0, 0, h]) {
|
||||||
|
for (i=[0,1,2,3]) {
|
||||||
|
rotate([0, 0, 90*i]) {
|
||||||
|
cube([0.2, 0.01, 0.07], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5126
data/mesh/rocket.stl
Normal file
5126
data/mesh/rocket.stl
Normal file
File diff suppressed because it is too large
Load diff
13
data/shader/background.frag
Normal file
13
data/shader/background.frag
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
uniform sampler2D texture;
|
||||||
|
|
||||||
|
varying vec3 vertex;
|
||||||
|
varying vec2 uv;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec3 color = texture2D(texture, uv).rgb;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color, 1.0);
|
||||||
|
}
|
12
data/shader/background.vert
Normal file
12
data/shader/background.vert
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#version 120
|
||||||
|
uniform vec2 uvScale;
|
||||||
|
|
||||||
|
varying vec3 vertex;
|
||||||
|
varying vec2 uv;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = gl_Vertex;
|
||||||
|
vertex = gl_Position.xyz;
|
||||||
|
uv = uvScale * (0.5 + vertex.xy / 2.0);
|
||||||
|
}
|
|
@ -10,6 +10,10 @@ uniform vec3 materialColor;
|
||||||
uniform int materialKind;
|
uniform int materialKind;
|
||||||
uniform int materialSeed;
|
uniform int materialSeed;
|
||||||
|
|
||||||
|
uniform int explLightsNum;
|
||||||
|
uniform vec3 explLightsPos[10];
|
||||||
|
uniform float explLightsIntensities[10];
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 Eye = normalize(-vertex);
|
vec3 Eye = normalize(-vertex);
|
||||||
|
@ -27,7 +31,31 @@ void main()
|
||||||
vec3 color = materialColor;
|
vec3 color = materialColor;
|
||||||
color = max(vec3(0.0), min(vec3(1.0), color));
|
color = max(vec3(0.0), min(vec3(1.0), color));
|
||||||
|
|
||||||
vec3 IDiffuse = vec3(color) * lightColor * max(dot(normal, lightDirection), 0.0);
|
vec3 light = lightColor * max(dot(normal, lightDirection), 0.0);
|
||||||
|
//vec3 light = vec3(0.0);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0; i<explLightsNum; i++) {
|
||||||
|
vec3 explLightColor = vec3(1.0, 0.5, 0.2);
|
||||||
|
vec3 diff = vertex - explLightsPos[i];
|
||||||
|
float l = 10.0*length(diff);
|
||||||
|
float dir = max(0.0, -dot(normal, diff));
|
||||||
|
float dp = max(0.0, 1.0-l);
|
||||||
|
|
||||||
|
float intensity = 10.0;
|
||||||
|
if (dp == 0.0) {
|
||||||
|
intensity *= dir;
|
||||||
|
} else {
|
||||||
|
intensity *= dp;
|
||||||
|
}
|
||||||
|
intensity /= 1.0 + 0.5*l*l;
|
||||||
|
|
||||||
|
light += intensity * pow(explLightsIntensities[i], 2.0) * explLightColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
light = max(vec3(0.0), light);
|
||||||
|
|
||||||
|
vec3 IDiffuse = vec3(color) * light;
|
||||||
|
|
||||||
// TODO make instensity/exponent as parameter
|
// TODO make instensity/exponent as parameter
|
||||||
//vec3 ISpecular = lightColor * 5.0 * pow(max(dot(Reflected, Eye), 0.0), 2.0);
|
//vec3 ISpecular = lightColor * 5.0 * pow(max(dot(Reflected, Eye), 0.0), 2.0);
|
||||||
|
|
|
@ -9,11 +9,12 @@ varying vec3 lightDirection;
|
||||||
|
|
||||||
uniform mat4 model;
|
uniform mat4 model;
|
||||||
uniform vec3 lightPosition;
|
uniform vec3 lightPosition;
|
||||||
|
uniform float aspectRatio;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// TODO: this becomes invalid when projection matrices are used
|
// TODO: this becomes invalid when projection matrices are used
|
||||||
vec3 p = (model*vec4(in_vertex, 1.0)).xyz;
|
vec3 p = (model*vec4(in_vertex/vec3(aspectRatio, 1.0, 1.0), 1.0)).xyz;
|
||||||
lightDirection = normalize(lightPosition - p);
|
lightDirection = normalize(lightPosition - p);
|
||||||
|
|
||||||
vertex = p.xyz;
|
vertex = p.xyz;
|
||||||
|
|
|
@ -4,7 +4,8 @@ varying vec3 velocity;
|
||||||
varying float decay;
|
varying float decay;
|
||||||
|
|
||||||
varying float explCenterDist;
|
varying float explCenterDist;
|
||||||
uniform vec3 explCenter;
|
|
||||||
|
float pi = 3.14159;
|
||||||
|
|
||||||
vec3 hsv2rgb(vec3 c)
|
vec3 hsv2rgb(vec3 c)
|
||||||
{
|
{
|
||||||
|
@ -13,15 +14,28 @@ vec3 hsv2rgb(vec3 c)
|
||||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float hash(float n)
|
||||||
|
{
|
||||||
|
return fract(sin(n)*43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
float r = length(vertex);
|
// normalize radius from 0..1
|
||||||
if (r > 1.0) {
|
vec2 vn = 2.0*vertex;
|
||||||
|
float rn = length(vn);
|
||||||
|
float angle = atan(vn.y, vn.x);
|
||||||
|
float hs = 20.0;
|
||||||
|
float removeCorners = 0.5 * (hash(fract(hs*vertex.x)) + hash(fract(hs*vertex.y)));
|
||||||
|
if (rn+removeCorners > 1.0) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//float rf = 0.5-0.5*rn;
|
||||||
|
float rf = 1.0;
|
||||||
|
|
||||||
float d = decay/(1.0+max(0.0, 1.0-2.0*explCenterDist));
|
float d = decay/(1.0+max(0.0, 1.0-2.0*explCenterDist));
|
||||||
float h = (1.0-d)/6.0;
|
float h = max(0.0, (1.0-d)/6.0) * rf;
|
||||||
float v = max(0.0, (1.0-log(d)));
|
float v = max(0.0, (1.0-log(d)));
|
||||||
float s = max(0.0, min(30.0 * sqrt(decay) * explCenterDist, 1.0));
|
float s = max(0.0, min(30.0 * sqrt(decay) * explCenterDist, 1.0));
|
||||||
|
|
||||||
|
@ -31,4 +45,5 @@ void main()
|
||||||
gl_FragColor = vec4(hsv2rgb(vec3(h, s, v)), 1.0);
|
gl_FragColor = vec4(hsv2rgb(vec3(h, s, v)), 1.0);
|
||||||
|
|
||||||
//gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
//gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
||||||
|
//gl_FragColor.rgb = vec3(0.5+0.5*(a/pi));
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
#version 120
|
#version 120
|
||||||
attribute vec2 in_vertex;
|
attribute vec2 in_geometry;
|
||||||
attribute vec3 in_position;
|
attribute vec3 in_position;
|
||||||
attribute vec3 in_velocity;
|
attribute vec3 in_velocity;
|
||||||
|
attribute float in_maxDist;
|
||||||
|
|
||||||
uniform float age;
|
uniform float age;
|
||||||
uniform float size;
|
uniform float size;
|
||||||
|
@ -14,6 +15,8 @@ varying vec3 velocity;
|
||||||
varying vec2 vertex;
|
varying vec2 vertex;
|
||||||
varying float explCenterDist;
|
varying float explCenterDist;
|
||||||
|
|
||||||
|
uniform float aspectRatio;
|
||||||
|
|
||||||
// TODO: rotate to face the user!
|
// TODO: rotate to face the user!
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
@ -26,11 +29,17 @@ void main()
|
||||||
decay = ageMod / halfAge;
|
decay = ageMod / halfAge;
|
||||||
|
|
||||||
// faster particles are smaller
|
// faster particles are smaller
|
||||||
|
// TODO: scale by time too! scale down fast after 3 halfAges
|
||||||
float scaleBySpeed = (1.0 - 0.95*length(in_velocity)/maxVelocity);
|
float scaleBySpeed = (1.0 - 0.95*length(in_velocity)/maxVelocity);
|
||||||
float finalSize = size * scaleBySpeed;
|
float finalSize = size * scaleBySpeed * (1.0-max(0.0, decay-3.0*halfAge)/2.0);
|
||||||
vec2 base = in_vertex;
|
vec2 base = in_geometry;
|
||||||
vec3 p = finalSize*vec3(base, 0.0);
|
vec3 p = vec3(finalSize*base, 0.0);
|
||||||
vec3 offset = (0.2*age + log(1.0+age*5.0)) * in_velocity + in_position;
|
vec3 move = (0.2*age + log(1.0+age*5.0)) * in_velocity;
|
||||||
|
float md = length(move);
|
||||||
|
if (md > in_maxDist) {
|
||||||
|
move *= in_maxDist / md;
|
||||||
|
}
|
||||||
|
vec3 offset = move + in_position;
|
||||||
p += offset;
|
p += offset;
|
||||||
|
|
||||||
gl_Position = vec4(p, 1.0);
|
gl_Position = vec4(p, 1.0);
|
||||||
|
|
|
@ -4,6 +4,7 @@ find_package(OpenGL REQUIRED)
|
||||||
find_package(epoxy REQUIRED)
|
find_package(epoxy REQUIRED)
|
||||||
find_package(X11 REQUIRED)
|
find_package(X11 REQUIRED)
|
||||||
find_package(assimp REQUIRED)
|
find_package(assimp REQUIRED)
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
|
||||||
set(GAME_SRC
|
set(GAME_SRC
|
||||||
main.cpp
|
main.cpp
|
||||||
|
@ -11,14 +12,22 @@ set(GAME_SRC
|
||||||
glclasses.cpp
|
glclasses.cpp
|
||||||
game_window.cpp
|
game_window.cpp
|
||||||
renderer.cpp
|
renderer.cpp
|
||||||
|
|
||||||
|
developer_console.cpp
|
||||||
|
|
||||||
renderer_polygon_2d/renderer_polygon_2d.cpp
|
renderer_polygon_2d/renderer_polygon_2d.cpp
|
||||||
|
|
||||||
renderer_polygon_3d/renderer_polygon_3d.cpp
|
renderer_polygon_3d/renderer_polygon_3d.cpp
|
||||||
renderer_polygon_3d/polygon_model.cpp
|
renderer_polygon_3d/polygon_model.cpp
|
||||||
renderer_polygon_3d/particle_batch.cpp
|
renderer_polygon_3d/particle_batch.cpp
|
||||||
|
renderer_polygon_3d/image_texture.cpp
|
||||||
|
|
||||||
renderer_ray_tracer/renderer_ray_tracer.cpp
|
renderer_ray_tracer/renderer_ray_tracer.cpp
|
||||||
|
|
||||||
network/session.cpp
|
network/session.cpp
|
||||||
|
|
||||||
|
sound/sound_effects.cpp
|
||||||
|
|
||||||
util.cpp
|
util.cpp
|
||||||
game.cpp
|
game.cpp
|
||||||
|
|
||||||
|
@ -33,9 +42,17 @@ set(GAME_SRC
|
||||||
state/state.cpp
|
state/state.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(SOUND_LIBRARIES "")
|
||||||
|
|
||||||
|
# TODO: make optional!
|
||||||
|
#set(GAME_SRC ${GAME_SRC} sound/sound.cpp)
|
||||||
|
#set(SOUND_LIBRARIES -lportaudio -lsndfile)
|
||||||
|
set(GAME_SRC ${GAME_SRC} sound/dummy_sound.cpp)
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
include_directories(${OPENGL_INCLUDE_DIR})
|
include_directories(${OPENGL_INCLUDE_DIR})
|
||||||
|
include_directories(${PNG_INCLUDE_DIR})
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/libs/glm/)
|
include_directories(${CMAKE_SOURCE_DIR}/libs/glm/)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/libs/asio/asio/include/)
|
include_directories(${CMAKE_SOURCE_DIR}/libs/asio/asio/include/)
|
||||||
include_directories(${assimp_INCLUDE_DIRS})
|
include_directories(${assimp_INCLUDE_DIRS})
|
||||||
|
@ -43,4 +60,5 @@ include_directories(${assimp_INCLUDE_DIRS})
|
||||||
add_executable(game ${GAME_SRC})
|
add_executable(game ${GAME_SRC})
|
||||||
setup_target(game)
|
setup_target(game)
|
||||||
|
|
||||||
target_link_libraries(game X11 epoxy pthread ${assimp_LIBRARIES} assimp)
|
target_link_libraries(game X11 epoxy pthread ${assimp_LIBRARIES} assimp
|
||||||
|
${SOUND_LIBRARIES} ${PNG_LIBRARIES})
|
||||||
|
|
74
game/developer_console.cpp
Normal file
74
game/developer_console.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "developer_console.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
namespace developer {
|
||||||
|
DeveloperConsole s_instance;
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult DeveloperConsole::CallbackResult::createError(const std::string &answer)
|
||||||
|
{
|
||||||
|
return CallbackResult(false, answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult DeveloperConsole::CallbackResult::createOkay(const std::string &answer)
|
||||||
|
{
|
||||||
|
return CallbackResult(true, answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult::CallbackResult(bool okay, const std::string &answer)
|
||||||
|
: okay(okay), answer(answer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DeveloperConsole::DeveloperConsole()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// static thing.
|
||||||
|
DeveloperConsole &DeveloperConsole::instance() {
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeveloperConsole::addCallback(const std::string &token, callback_t cb)
|
||||||
|
{
|
||||||
|
bool hasWhitespace = false;
|
||||||
|
for (size_t i=0; i<token.size(); i++) {
|
||||||
|
if (isspace(token[i])) {
|
||||||
|
hasWhitespace = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cbIsNull = (cb == nullptr);
|
||||||
|
bool tokenEmpty = token.empty();
|
||||||
|
|
||||||
|
if (hasWhitespace || cbIsNull || tokenEmpty) {
|
||||||
|
std::cout << "not registering bad token/cb comibnation for: " << token << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout<<"[developer console] adding developer "
|
||||||
|
"callback for token '" << token << "'" << std::endl;
|
||||||
|
|
||||||
|
m_callbacks[token] = cb;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult DeveloperConsole::dispatchInput(const std::string &token, const std::string &payload)
|
||||||
|
{
|
||||||
|
std::map<std::string, DeveloperConsole::callback_t>::iterator it = m_callbacks.find(token);
|
||||||
|
if (it == m_callbacks.end()) {
|
||||||
|
return DeveloperConsole::CallbackResult::createError("unknown command with token: '" + token + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->second(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult resultOkay()
|
||||||
|
{
|
||||||
|
return DeveloperConsole::CallbackResult::createOkay();
|
||||||
|
}
|
||||||
|
}
|
49
game/developer_console.hpp
Normal file
49
game/developer_console.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// stuff in namespace "developer" can be disabled and the game must function in
|
||||||
|
// exact the same way just without cool debug features.
|
||||||
|
namespace developer {
|
||||||
|
class DeveloperConsole {
|
||||||
|
public:
|
||||||
|
class CallbackResult {
|
||||||
|
private:
|
||||||
|
CallbackResult(bool okay, const std::string &answer);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CallbackResult createError(const std::string &answer="");
|
||||||
|
static CallbackResult createOkay(const std::string &answer="");
|
||||||
|
|
||||||
|
public:
|
||||||
|
// read-only interface to result data
|
||||||
|
const bool okay;
|
||||||
|
const std::string answer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<CallbackResult(const std::string &cmd)> callback_t;
|
||||||
|
|
||||||
|
DeveloperConsole();
|
||||||
|
|
||||||
|
// access functionality over this static singleton attribute to make
|
||||||
|
// it really easy and fast to use
|
||||||
|
static DeveloperConsole &instance();
|
||||||
|
|
||||||
|
// register callback for a token.
|
||||||
|
// token must not have whitespace in it and not be empty.
|
||||||
|
// old callback will be overridden if any
|
||||||
|
// return true on succes, false if not saved.
|
||||||
|
bool addCallback(const std::string &token, callback_t cb);
|
||||||
|
|
||||||
|
// dispatch input received over a communication channel.
|
||||||
|
CallbackResult dispatchInput(const std::string &token, const std::string &payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, callback_t> m_callbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
DeveloperConsole::CallbackResult resultOkay();
|
||||||
|
}
|
|
@ -80,3 +80,7 @@ bool Game::cycle(float dt)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
void Game::resize(int width, int height)
|
||||||
|
{
|
||||||
|
m_state->setPlayingFieldSize(width, height);
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ class Game {
|
||||||
// for rendering
|
// for rendering
|
||||||
game::State *state() const { return m_state; }
|
game::State *state() const { return m_state; }
|
||||||
|
|
||||||
|
// resize the playing field
|
||||||
|
void resize(int width, int height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
game::State *m_state;
|
game::State *m_state;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,21 @@ class GameWindow : public endofthejedi::GLWindow {
|
||||||
m_renderer.render(m_game->state());
|
m_renderer.render(m_game->state());
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize() override { glViewport(0, 0, getwidth(), getheight()); }
|
void resize() override
|
||||||
|
{
|
||||||
|
std::cout<<"resize()" << std::endl;
|
||||||
|
|
||||||
|
glViewport(0, 0, getwidth(), getheight());
|
||||||
|
|
||||||
|
// resize the game
|
||||||
|
m_game->resize(getwidth(), getheight());
|
||||||
|
|
||||||
|
// TODO: mark it and let the reinit() happen in the next so it happnens just once. while doing the resize
|
||||||
|
m_game->state()->init();
|
||||||
|
|
||||||
|
// resize the renderer
|
||||||
|
m_renderer.setWindowSize(getwidth(), getheight());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameWindow(unsigned int width, unsigned int height, Game *ptr)
|
GameWindow(unsigned int width, unsigned int height, Game *ptr)
|
||||||
|
|
|
@ -6,17 +6,16 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace endofthejedi {
|
namespace endofthejedi {
|
||||||
VAO::VAO() { glGenVertexArrays(1, &m_name); }
|
|
||||||
|
|
||||||
|
VAO::VAO() {}
|
||||||
VAO::~VAO() { glDeleteVertexArrays(1, &m_name); }
|
VAO::~VAO() { glDeleteVertexArrays(1, &m_name); }
|
||||||
|
|
||||||
|
void VAO::init() { glGenVertexArrays(1, &m_name); }
|
||||||
void VAO::bind() { glBindVertexArray(m_name); }
|
void VAO::bind() { glBindVertexArray(m_name); }
|
||||||
void VAO::unbind() { glBindVertexArray(0); }
|
void VAO::unbind() { glBindVertexArray(0); }
|
||||||
|
|
||||||
void VAO::fill(GLuint index, GLint size, GLenum type,
|
void VAO::fill(GLuint index, GLint size, GLenum type, GLboolean normalized,
|
||||||
GLboolean normalized, GLsizei stride,
|
GLsizei stride, const GLvoid *pointer) {
|
||||||
const GLvoid *pointer)
|
|
||||||
{
|
|
||||||
glEnableVertexAttribArray(index);
|
glEnableVertexAttribArray(index);
|
||||||
glVertexAttribPointer(index, size, type, normalized, stride, pointer);
|
glVertexAttribPointer(index, size, type, normalized, stride, pointer);
|
||||||
}
|
}
|
||||||
|
@ -65,8 +64,7 @@ namespace endofthejedi {
|
||||||
return result != GL_FALSE;
|
return result != GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::bind()
|
void Shader::bind() {
|
||||||
{
|
|
||||||
if (m_program == 0) {
|
if (m_program == 0) {
|
||||||
std::cerr << "error: invalid to bind invalid program (0)! "
|
std::cerr << "error: invalid to bind invalid program (0)! "
|
||||||
"use unbind() if that was your purpose!" << std::endl;
|
"use unbind() if that was your purpose!" << std::endl;
|
||||||
|
@ -84,7 +82,8 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void Shader::load(const std::string &data, GLenum shadertype) {
|
void Shader::load(const std::string &data, GLenum shadertype) {
|
||||||
if (m_program == 0) {
|
if (m_program == 0) {
|
||||||
std::cout<<"[shader] error: shader program is invalid (0)!" << std::endl;
|
std::cout << "[shader] error: shader program is invalid (0)!"
|
||||||
|
<< std::endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +107,8 @@ namespace endofthejedi {
|
||||||
std::ifstream fileStream(path, std::ios::in);
|
std::ifstream fileStream(path, std::ios::in);
|
||||||
|
|
||||||
if (!fileStream.is_open()) {
|
if (!fileStream.is_open()) {
|
||||||
std::cerr << "Could not read file " << path << ". File does not exist." << std::endl;
|
std::cerr << "Could not read file " << path << ". File does not exist."
|
||||||
|
<< std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,17 +125,67 @@ namespace endofthejedi {
|
||||||
GLuint Shader::location(const std::string &name) {
|
GLuint Shader::location(const std::string &name) {
|
||||||
return glGetUniformLocation(m_program, name.c_str());
|
return glGetUniformLocation(m_program, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture::Texture() {}
|
||||||
|
|
||||||
|
Texture::~Texture() { glDeleteTextures(1, &m_name); }
|
||||||
|
|
||||||
|
void Texture::init() { glGenTextures(1, &m_name); }
|
||||||
|
|
||||||
|
void Texture::bind() { glBindTexture(GL_TEXTURE_2D, m_name); }
|
||||||
|
|
||||||
|
void Texture::unbind() { glBindTexture(GL_TEXTURE_2D, 0); }
|
||||||
|
|
||||||
|
void Texture::fill(GLint level, GLint internalFormat, GLsizei width,
|
||||||
|
GLsizei height, GLint border, GLenum format, GLenum type,
|
||||||
|
const GLvoid *data) {
|
||||||
|
bind();
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, border,
|
||||||
|
format, type, data);
|
||||||
|
}
|
||||||
|
GLuint Texture::getName() { return m_name; }
|
||||||
|
|
||||||
|
Framebuffer::Framebuffer() {}
|
||||||
|
Framebuffer::~Framebuffer() { glDeleteFramebuffers(1, &m_name); }
|
||||||
|
|
||||||
|
void Framebuffer::init() { glGenFramebuffers(1, &m_name); }
|
||||||
|
void Framebuffer::bind() { glBindFramebuffer(GL_FRAMEBUFFER, m_name); }
|
||||||
|
|
||||||
|
void Framebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
|
||||||
|
|
||||||
|
void Framebuffer::attachRenderbuffer(GLenum attachment, GLuint rbo) {
|
||||||
|
bind();
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printGlError(GLenum err)
|
void Framebuffer::attachTexture(GLenum attachment, GLuint tex) {
|
||||||
{
|
bind();
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderbuffer::Renderbuffer() {}
|
||||||
|
|
||||||
|
Renderbuffer::~Renderbuffer() { glDeleteRenderbuffers(1, &m_name); }
|
||||||
|
|
||||||
|
void Renderbuffer::init() { glGenRenderbuffers(1, &m_name); }
|
||||||
|
void Renderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, m_name); }
|
||||||
|
|
||||||
|
void Renderbuffer::unbind() { glBindRenderbuffer(GL_RENDERBUFFER, 0); }
|
||||||
|
|
||||||
|
void Renderbuffer::create(GLenum internalformat, GLsizei width,
|
||||||
|
GLsizei height) {
|
||||||
|
bind();
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, internalformat, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printGlError(GLenum err) {
|
||||||
if (err != GL_NO_ERROR) {
|
if (err != GL_NO_ERROR) {
|
||||||
std::cout << "opengl error is: " << stringFromGlError(err) << std::endl;
|
std::cout << "opengl error is: " << stringFromGlError(err) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void discardLastGlError(bool print)
|
void discardLastGlError(bool print) {
|
||||||
{
|
|
||||||
GLenum err = glGetError();
|
GLenum err = glGetError();
|
||||||
if (print) {
|
if (print) {
|
||||||
printGlError(err);
|
printGlError(err);
|
||||||
|
@ -143,8 +193,7 @@ void discardLastGlError(bool print)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return false if there's an error
|
// return false if there's an error
|
||||||
bool checkAndPrintGlError()
|
bool checkAndPrintGlError() {
|
||||||
{
|
|
||||||
GLenum err = glGetError();
|
GLenum err = glGetError();
|
||||||
|
|
||||||
printGlError(err);
|
printGlError(err);
|
||||||
|
@ -152,15 +201,25 @@ bool checkAndPrintGlError()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *stringFromGlError(GLenum err)
|
const char *stringFromGlError(GLenum err) {
|
||||||
{
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; break;
|
case GL_INVALID_ENUM:
|
||||||
case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; break;
|
return "GL_INVALID_ENUM";
|
||||||
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; break;
|
break;
|
||||||
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; break;
|
case GL_INVALID_VALUE:
|
||||||
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
|
return "GL_INVALID_VALUE";
|
||||||
default: return "<unknown>"; break;
|
break;
|
||||||
|
case GL_INVALID_OPERATION:
|
||||||
|
return "GL_INVALID_OPERATION";
|
||||||
|
break;
|
||||||
|
case GL_OUT_OF_MEMORY:
|
||||||
|
return "GL_OUT_OF_MEMORY";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||||
|
return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "<unknown>";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ template <GLenum T> class BufferObject {
|
||||||
public:
|
public:
|
||||||
BufferObject();
|
BufferObject();
|
||||||
~BufferObject();
|
~BufferObject();
|
||||||
|
void init();
|
||||||
void bind();
|
void bind();
|
||||||
void bind(GLuint index, GLintptr offset = 0, GLsizeiptr size = 0);
|
void bind(GLuint index, GLintptr offset = 0, GLsizeiptr size = 0);
|
||||||
void fill(GLenum usage, GLsizei size = 0, GLvoid *data = NULL);
|
void fill(GLenum usage, GLsizei size = 0, GLvoid *data = NULL);
|
||||||
|
@ -35,6 +36,7 @@ class VAO {
|
||||||
public:
|
public:
|
||||||
VAO();
|
VAO();
|
||||||
~VAO();
|
~VAO();
|
||||||
|
void init();
|
||||||
void bind();
|
void bind();
|
||||||
void unbind();
|
void unbind();
|
||||||
void fill(GLuint index, GLint size, GLenum type, GLboolean normalized,
|
void fill(GLuint index, GLint size, GLenum type, GLboolean normalized,
|
||||||
|
@ -61,16 +63,63 @@ class Shader {
|
||||||
GLuint location(const std::string &name);
|
GLuint location(const std::string &name);
|
||||||
GLuint program();
|
GLuint program();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Texture {
|
||||||
|
private:
|
||||||
|
GLuint m_name;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
public:
|
||||||
|
Texture();
|
||||||
|
~Texture();
|
||||||
|
void init();
|
||||||
|
void bind();
|
||||||
|
void unbind();
|
||||||
|
void fill(GLint level, GLint internalFormat, GLsizei width, GLsizei height,
|
||||||
|
GLint border, GLenum format, GLenum type, const GLvoid *data);
|
||||||
|
GLuint getName();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Framebuffer {
|
||||||
|
private:
|
||||||
|
GLuint m_name;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
public:
|
||||||
|
Framebuffer();
|
||||||
|
~Framebuffer();
|
||||||
|
void init();
|
||||||
|
void bind();
|
||||||
|
void unbind();
|
||||||
|
void attachRenderbuffer(GLenum attachment, GLuint rbo);
|
||||||
|
void attachTexture(GLenum attachment, GLuint tex);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Renderbuffer {
|
||||||
|
private:
|
||||||
|
GLuint m_name;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
public:
|
||||||
|
Renderbuffer();
|
||||||
|
~Renderbuffer();
|
||||||
|
void init();
|
||||||
|
void bind();
|
||||||
|
void unbind();
|
||||||
|
void create(GLenum internalformat, GLsizei width, GLsizei height);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TBufferObject_(pre, post) \
|
#define TBufferObject_(pre, post) \
|
||||||
template <GLenum T> pre endofthejedi::BufferObject<T>::post
|
template <GLenum T> pre endofthejedi::BufferObject<T>::post
|
||||||
#define TBufferObject(...) TBufferObject_(__VA_ARGS__)
|
#define TBufferObject(...) TBufferObject_(__VA_ARGS__)
|
||||||
|
|
||||||
TBufferObject(, BufferObject)() { glGenBuffers(1, &m_name); }
|
TBufferObject(, BufferObject)() {}
|
||||||
|
|
||||||
TBufferObject(, ~BufferObject)() { glDeleteBuffers(1, &m_name); }
|
TBufferObject(, ~BufferObject)() { glDeleteBuffers(1, &m_name); }
|
||||||
|
|
||||||
|
TBufferObject(void, init)() { glGenBuffers(1, &m_name); }
|
||||||
|
|
||||||
TBufferObject(void, bind)() { glBindBuffer(T, m_name); }
|
TBufferObject(void, bind)() { glBindBuffer(T, m_name); }
|
||||||
|
|
||||||
TBufferObject(void, bind)(GLuint index, GLintptr offset, GLsizeiptr size) {
|
TBufferObject(void, bind)(GLuint index, GLintptr offset, GLsizeiptr size) {
|
||||||
|
@ -102,4 +151,3 @@ bool checkAndPrintGlError();
|
||||||
void printGlError(GLenum err);
|
void printGlError(GLenum err);
|
||||||
|
|
||||||
const char *stringFromGlError(GLenum err);
|
const char *stringFromGlError(GLenum err);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
#include "network/server.hpp"
|
#include "network/server.hpp"
|
||||||
#include "options.hpp"
|
#include "options.hpp"
|
||||||
|
|
||||||
|
#include "sound/sound.hpp"
|
||||||
|
#include "sound/sound_effects.hpp"
|
||||||
|
|
||||||
|
#include "state/state_update_event.hpp"
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
uint64_t optionsFlags;
|
uint64_t optionsFlags;
|
||||||
|
@ -19,6 +24,7 @@ using asio::ip::tcp;
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
bool devMode = false;
|
bool devMode = false;
|
||||||
|
bool soundEnabled = false;
|
||||||
char port[]="3490";
|
char port[]="3490";
|
||||||
|
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
|
@ -33,6 +39,7 @@ int main(int argc, char *argv[])
|
||||||
// {"delete", required_argument, 0, 'd'},
|
// {"delete", required_argument, 0, 'd'},
|
||||||
{"autorun", required_argument, 0, 'a'},
|
{"autorun", required_argument, 0, 'a'},
|
||||||
{"port", required_argument, 0, 'p'},
|
{"port", required_argument, 0, 'p'},
|
||||||
|
{"sound", no_argument, 0, 's'},
|
||||||
{"fps", no_argument, 0, 'f'},
|
{"fps", no_argument, 0, 'f'},
|
||||||
{"dev", no_argument, 0, 'd'},
|
{"dev", no_argument, 0, 'd'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
|
@ -41,7 +48,7 @@ int main(int argc, char *argv[])
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
char c = getopt_long (argc, argv, "p:fad",
|
char c = getopt_long (argc, argv, "p:fads",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -51,6 +58,7 @@ int main(int argc, char *argv[])
|
||||||
case 'f':
|
case 'f':
|
||||||
SET_FLAG(SHOW_FPS,true);
|
SET_FLAG(SHOW_FPS,true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
std::cout<<"enabling developer mode" << std::endl;
|
std::cout<<"enabling developer mode" << std::endl;
|
||||||
devMode = true;
|
devMode = true;
|
||||||
|
@ -60,6 +68,10 @@ int main(int argc, char *argv[])
|
||||||
strcpy(port,optarg);
|
strcpy(port,optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
soundEnabled = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
SET_FLAG(TEST_AUTORUN, true);
|
SET_FLAG(TEST_AUTORUN, true);
|
||||||
break;
|
break;
|
||||||
|
@ -75,6 +87,13 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
|
sound::SoundEffects *sounds = nullptr;
|
||||||
|
if (soundEnabled) {
|
||||||
|
if (sound::initSound()) {
|
||||||
|
sounds = new sound::SoundEffects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Game game;
|
Game game;
|
||||||
game.state()->setDeveloperMode(devMode);
|
game.state()->setDeveloperMode(devMode);
|
||||||
|
|
||||||
|
@ -89,6 +108,23 @@ int main(int argc, char *argv[])
|
||||||
while(window.running()){
|
while(window.running()){
|
||||||
window.poll();
|
window.poll();
|
||||||
io_service.poll();
|
io_service.poll();
|
||||||
|
|
||||||
|
//size_t numEvents = game.state()->currentStateUpdateEvents().size();
|
||||||
|
//if (numEvents != 0) {
|
||||||
|
// std::cout<<"game state update events: " << numEvents << std::endl;
|
||||||
|
// for (game::StateUpdateEvent *evt : game.state()->currentStateUpdateEvents()) {
|
||||||
|
// std::cout<< evt->description() << std::endl;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (sounds != nullptr) {
|
||||||
|
// TODO: get time diff too
|
||||||
|
sounds->advance(1/50.0f, game.state()->currentStateUpdateEvents());
|
||||||
|
// TODO: use flag to now when to do this.
|
||||||
|
sound::deleteOldSounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
game.state()->applyAndClearAllOldStateUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
#include "session.hpp"
|
#include "session.hpp"
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
#include "state/commands.hpp"
|
#include "state/commands.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
void trim(std::string &str)
|
void trim(std::string &str)
|
||||||
{
|
{
|
||||||
const std::string ws = " \t\r\n";
|
const std::string ws = " \t\r\n";
|
||||||
|
@ -28,13 +27,10 @@ bool Session::parse(std::string s)
|
||||||
// strip leading/trailing whitespace/newlines as they are always unintional
|
// strip leading/trailing whitespace/newlines as they are always unintional
|
||||||
trim(s);
|
trim(s);
|
||||||
|
|
||||||
std::istringstream iss(s);
|
|
||||||
|
|
||||||
std::string token;
|
std::string token;
|
||||||
iss >> token;
|
std::string rest;
|
||||||
|
|
||||||
// skip token + next whitespace
|
util::splitIntoTokenAndRest(s, token, rest);
|
||||||
std::string rest = s.substr(std::min(s.size(), token.size()+1));
|
|
||||||
|
|
||||||
//std::cout<<"[session] token='" << token << "' rest='" << rest << "'" << std::endl;
|
//std::cout<<"[session] token='" << token << "' rest='" << rest << "'" << std::endl;
|
||||||
|
|
||||||
|
|
|
@ -33,5 +33,5 @@ private:
|
||||||
char m_rcv_data[max_length];
|
char m_rcv_data[max_length];
|
||||||
game::State* m_state;
|
game::State* m_state;
|
||||||
bool m_started = false;
|
bool m_started = false;
|
||||||
int m_pid;
|
size_t m_pid;
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,8 +99,9 @@ namespace endofthejedi {
|
||||||
m_width = attribs.width;
|
m_width = attribs.width;
|
||||||
m_height = attribs.height;
|
m_height = attribs.height;
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
} else if (event.type == ClientMessage) {
|
} else if (event.type == ClientMessage) {
|
||||||
if (event.xclient.data.l[0] == m_atomWmDeleteWindow) {
|
if (event.xclient.data.l[0] == (int) m_atomWmDeleteWindow) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
} else if (event.type == DestroyNotify) {
|
} else if (event.type == DestroyNotify) {
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <epoxy/gl.h>
|
#include <epoxy/gl.h>
|
||||||
#include <epoxy/glx.h>
|
#include <epoxy/glx.h>
|
||||||
|
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
|
|
||||||
namespace endofthejedi {
|
namespace endofthejedi {
|
||||||
|
@ -21,6 +23,9 @@ namespace endofthejedi {
|
||||||
public:
|
public:
|
||||||
virtual void setup() { }
|
virtual void setup() { }
|
||||||
virtual void render(const game::State *state) = 0;
|
virtual void render(const game::State *state) = 0;
|
||||||
|
|
||||||
|
virtual void setWindowSize(int px, int py) { (void) px; (void) py; }
|
||||||
|
virtual void setCameraMatrix(const glm::mat4 &cam) { (void) cam; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
159
game/renderer_polygon_3d/image_texture.cpp
Normal file
159
game/renderer_polygon_3d/image_texture.cpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#include "image_texture.hpp"
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace endofthejedi {
|
||||||
|
|
||||||
|
bool ImageTexture::loadPng()
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
|
||||||
|
//header for testing if it is a png
|
||||||
|
png_byte header[8];
|
||||||
|
|
||||||
|
//open file as binary
|
||||||
|
FILE *fp = fopen(m_path.c_str(), "rb");
|
||||||
|
if (!fp) {
|
||||||
|
printf("[image_texture] warning: could not open png file to load: %s\n", m_path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the header
|
||||||
|
fread(header, 1, 8, fp);
|
||||||
|
|
||||||
|
//test if png
|
||||||
|
int is_png = !png_sig_cmp(header, 0, 8);
|
||||||
|
if (!is_png) {
|
||||||
|
puts("warning: image loader: file is not PNG!");
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create png struct
|
||||||
|
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!png_ptr) {
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create png info struct
|
||||||
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (!info_ptr) {
|
||||||
|
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create png info struct
|
||||||
|
png_infop end_info = png_create_info_struct(png_ptr);
|
||||||
|
if (!end_info) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//png error stuff, not sure libpng man suggests this.
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//init png reading
|
||||||
|
png_init_io(png_ptr, fp);
|
||||||
|
|
||||||
|
//let libpng know you already read the first 8 bytes
|
||||||
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
|
|
||||||
|
// read all the info up to the image data
|
||||||
|
png_read_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//variables to pass to get info
|
||||||
|
int bit_depth, color_type;
|
||||||
|
png_uint_32 twidth, theight;
|
||||||
|
|
||||||
|
// get info about png
|
||||||
|
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
//update width and height based on png info
|
||||||
|
m_size = glm::vec2(twidth, theight);
|
||||||
|
|
||||||
|
int pot_width = (int) pow(2, ceilf(log2f(m_size.x)));
|
||||||
|
int pot_height = (int) pow(2, ceilf(log2f(m_size.y)));
|
||||||
|
|
||||||
|
m_uvScale = m_size / glm::vec2(pot_width, pot_height);
|
||||||
|
|
||||||
|
/*puts("#########################################");*/
|
||||||
|
/*printf("# PNG: width=%d, height=%d\n", width, height);*/
|
||||||
|
/*printf("# powers of two: w=%d, h=%d\n", pot_width, pot_height);*/
|
||||||
|
/*puts("#########################################");*/
|
||||||
|
|
||||||
|
// Update the png info struct.
|
||||||
|
png_read_update_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// Row size in bytes.
|
||||||
|
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
int pot_rowbytes = 4 * (int) pow(2, ceilf(log2f(rowbytes/4)));
|
||||||
|
/*printf("rowbytes: %d, pot_rowbytes=%d\n", rowbytes, pot_rowbytes);*/
|
||||||
|
|
||||||
|
// Allocate the image_data as a big block, to be given to opengl
|
||||||
|
png_byte *image_data = (png_byte *) calloc(pot_rowbytes * pot_height, sizeof(png_byte));
|
||||||
|
if (!image_data) {
|
||||||
|
//clean up memory and close stuff
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//row_pointers is for pointing to image_data for reading the png with libpng
|
||||||
|
png_bytep *row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * theight);
|
||||||
|
if (!row_pointers) {
|
||||||
|
//clean up memory and close stuff
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
|
free(image_data);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the individual row_pointers to point at the correct offsets of image_data
|
||||||
|
for (uint32_t i = 0; i < theight; ++i) {
|
||||||
|
row_pointers[theight- 1 - i] = image_data + i * pot_rowbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the png into image_data through row_pointers
|
||||||
|
png_read_image(png_ptr, row_pointers);
|
||||||
|
|
||||||
|
//Now generate the OpenGL texture object
|
||||||
|
glGenTextures(1, &m_texture_id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_texture_id);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
pot_width,
|
||||||
|
pot_height,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
(GLvoid*) image_data);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
// TODO: make selectable via switch!
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||||
|
|
||||||
|
//clean up memory and close stuff
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
|
free(image_data);
|
||||||
|
free(row_pointers);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
m_valid = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
63
game/renderer_polygon_3d/image_texture.hpp
Normal file
63
game/renderer_polygon_3d/image_texture.hpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "glclasses.hpp"
|
||||||
|
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
|
// based on sources of knoc/chaqu
|
||||||
|
|
||||||
|
namespace endofthejedi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This sprite struct stores all information needed to render an
|
||||||
|
* arbitrary PNG texture to a quad.
|
||||||
|
*
|
||||||
|
* If the loaded texture dimensions have no powers of a bit more space is
|
||||||
|
* allocated and extra padding is added.
|
||||||
|
*/
|
||||||
|
class ImageTexture {
|
||||||
|
public:
|
||||||
|
ImageTexture(const std::string &filename) : m_path(filename), m_valid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ImageTexture()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to load a PNG image from file into an opengl texture.
|
||||||
|
*
|
||||||
|
* @param path Path of PNG file
|
||||||
|
* @param texture The used texture id will be saved there.
|
||||||
|
* @param width Width of the loaded texture in pixels.
|
||||||
|
* @param height Height of the loaded texture in pixels.
|
||||||
|
* @param uv_scale_x Horizontal portion of the screen which is padded to get
|
||||||
|
* power-of-two texture.
|
||||||
|
* @param uv_scale_y Vertical portion of the screen which is padded to get
|
||||||
|
* power-of-two texture.
|
||||||
|
*
|
||||||
|
* Note: The current active texture unit should be bound (GL_TEXTURE0 etc...)
|
||||||
|
* before calling this
|
||||||
|
*
|
||||||
|
* @return true if loading suceeded, false on errors.
|
||||||
|
*/
|
||||||
|
bool loadPng();
|
||||||
|
|
||||||
|
bool valid() const { return m_valid; }
|
||||||
|
|
||||||
|
glm::vec2 size() const { return m_size; }
|
||||||
|
glm::vec2 uvScale() const { return m_uvScale; }
|
||||||
|
|
||||||
|
GLuint textureId() const { return m_texture_id; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string m_path; // path for the loaded texture is saved here
|
||||||
|
glm::vec2 m_size; // used width/height of the pixels of the texture
|
||||||
|
glm::vec2 m_uvScale; // factor to scale uv-coordinates to get rid of non-power-of-two padding
|
||||||
|
|
||||||
|
bool m_valid;
|
||||||
|
|
||||||
|
GLuint m_texture_id; // texture binding id
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// TODO: use VAO's as soon as this is working
|
// TODO: use VAO's as soon as this is working
|
||||||
|
|
||||||
int getDivisorForIndex(int index)
|
int getDivisorForIndex(size_t index)
|
||||||
{
|
{
|
||||||
// 0 or 1?
|
// 0 or 1?
|
||||||
return (index == 0) ? 0 : 3;
|
return (index == 0) ? 0 : 3;
|
||||||
|
@ -15,52 +15,63 @@ namespace endofthejedi {
|
||||||
: m_id(id)
|
: m_id(id)
|
||||||
, m_numParticles(numParticles)
|
, m_numParticles(numParticles)
|
||||||
, m_particleRadius(particleSize)
|
, m_particleRadius(particleSize)
|
||||||
, m_halfAge(halfAge)
|
|
||||||
, m_age(0.0)
|
, m_age(0.0)
|
||||||
|
, m_halfAge(halfAge)
|
||||||
|
|
||||||
|
// XXX this is used in some places in the shader.
|
||||||
|
// set it via uniform too
|
||||||
|
, m_maxNumHalfAges(5.0)
|
||||||
|
|
||||||
, m_maxVelocity(1.0)
|
, m_maxVelocity(1.0)
|
||||||
, m_center(glm::vec3(0.0f, 0.0f, 0.0f))
|
, m_center(glm::vec3(0.0f, 0.0f, 0.0f))
|
||||||
|
|
||||||
// 2d quad drawn as a triangle fan
|
// 2d quad drawn as a triangle fan.
|
||||||
, m_data_quad({
|
//
|
||||||
1.0f, -1.0f,
|
// TODO
|
||||||
1.0f, 1.0f,
|
// it is transformed before uploading so it looks at the camera
|
||||||
-1.0f, 1.0f,
|
, m_data_geometry({
|
||||||
-1.0f, -1.0f})
|
0.5f, -0.5f,
|
||||||
|
0.5f, 0.5f,
|
||||||
|
-0.5f, 0.5f,
|
||||||
|
-0.5f, -0.5f})
|
||||||
{
|
{
|
||||||
|
m_num_vertex_buffers = 4;
|
||||||
|
|
||||||
//std::cout<<"[ParticleBatch] create for " << numParticles << " num particles" << std::endl;
|
//std::cout<<"[ParticleBatch] create for " << numParticles << " num particles" << std::endl;
|
||||||
|
m_attr_locations.resize(m_num_vertex_buffers);
|
||||||
|
m_data_vbos.resize(m_num_vertex_buffers);
|
||||||
|
|
||||||
m_data_position.resize(m_numParticles);
|
m_data_position.resize(m_numParticles);
|
||||||
m_data_velocity.resize(m_numParticles);
|
m_data_velocity.resize(m_numParticles);
|
||||||
m_data_kind.resize(m_numParticles);
|
m_data_max_distance.resize(m_numParticles);
|
||||||
m_data_max_age.resize(m_numParticles);
|
|
||||||
|
|
||||||
std::string vss_particles = "../data/shader/particle.vert";
|
for (size_t i=0; i<m_num_vertex_buffers; i++) {
|
||||||
std::string fss_particles = "../data/shader/particle.frag";
|
m_attr_locations[i] = -1;
|
||||||
|
m_data_vbos[i] = 0;
|
||||||
m_shader.init();
|
|
||||||
m_shader.loadFile(vss_particles, GL_VERTEX_SHADER);
|
|
||||||
m_shader.loadFile(fss_particles, GL_FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
const char *names[] = {
|
|
||||||
"in_vertex",
|
|
||||||
"in_position",
|
|
||||||
"in_velocity",
|
|
||||||
"XXXunusedXXX",
|
|
||||||
"XXXunusedXXX"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
const char *name = names[i];
|
|
||||||
GLint loc = glGetAttribLocation(m_shader.program(), name);
|
|
||||||
m_attr_locations[i] = loc;
|
|
||||||
//std::cout<<"attr location " << i << " " << loc << " " << name << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParticleBatch::~ParticleBatch()
|
ParticleBatch::~ParticleBatch()
|
||||||
{
|
{
|
||||||
// TODO: find out if stuff must be deallocated
|
// TODO: find out if stuff must be deallocated
|
||||||
glDeleteBuffers(5, m_data_vbos);
|
glDeleteBuffers(m_num_vertex_buffers, m_data_vbos.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParticleBatch::setup(Shader *shader)
|
||||||
|
{
|
||||||
|
static const char *names[] = {
|
||||||
|
"in_geometry",
|
||||||
|
"in_position",
|
||||||
|
"in_velocity",
|
||||||
|
"in_maxDist"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i=0; i<m_num_vertex_buffers; i++) {
|
||||||
|
const char *name = names[i];
|
||||||
|
GLint loc = glGetAttribLocation(shader->program(), name);
|
||||||
|
m_attr_locations[i] = loc;
|
||||||
|
//std::cout<<"attr location for " << name << " (#" << i << ") is " << loc << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleBatch::setCenter(const glm::vec3 ¢er)
|
void ParticleBatch::setCenter(const glm::vec3 ¢er)
|
||||||
|
@ -73,7 +84,7 @@ namespace endofthejedi {
|
||||||
m_maxVelocity = maxVelocity;
|
m_maxVelocity = maxVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleBatch::setParticle(size_t index, const glm::vec3 &p, const glm::vec3 &v)
|
void ParticleBatch::setParticle(size_t index, const glm::vec3 &p, const glm::vec3 &v, float maxDist)
|
||||||
{
|
{
|
||||||
if (index >= m_numParticles) {
|
if (index >= m_numParticles) {
|
||||||
return;
|
return;
|
||||||
|
@ -83,15 +94,14 @@ namespace endofthejedi {
|
||||||
|
|
||||||
m_data_position[index] = p;
|
m_data_position[index] = p;
|
||||||
m_data_velocity[index] = v;
|
m_data_velocity[index] = v;
|
||||||
m_data_kind[index] = 0.0;
|
m_data_max_distance[index] = maxDist;
|
||||||
m_data_max_age[index] = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleBatch::bind()
|
void ParticleBatch::bind()
|
||||||
{
|
{
|
||||||
//std::cout<<"[ParticleBatch] bind" << std::endl;
|
//std::cout<<"[ParticleBatch] bind" << std::endl;
|
||||||
|
|
||||||
for (size_t i=0; i<5; i++) {
|
for (size_t i=0; i<m_num_vertex_buffers; i++) {
|
||||||
//std::cout<<"vbo #" << i << ": " << m_data_vbos[i] << std::endl;
|
//std::cout<<"vbo #" << i << ": " << m_data_vbos[i] << std::endl;
|
||||||
glEnableVertexAttribArray(m_attr_locations[i]);
|
glEnableVertexAttribArray(m_attr_locations[i]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]);
|
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]);
|
||||||
|
@ -113,9 +123,9 @@ namespace endofthejedi {
|
||||||
{
|
{
|
||||||
//std::cout<<"[ParticleBatch] upload to vbo's " << std::endl;
|
//std::cout<<"[ParticleBatch] upload to vbo's " << std::endl;
|
||||||
|
|
||||||
glGenBuffers(5, m_data_vbos); // Generate buffer
|
glGenBuffers(m_num_vertex_buffers, m_data_vbos.data()); // Generate buffer
|
||||||
|
|
||||||
for (size_t i=0; i<5; i++) {
|
for (size_t i=0; i<m_num_vertex_buffers; i++) {
|
||||||
size_t bufferDataSize = dataSizeForIndex(i) * m_numParticles * sizeof(float);
|
size_t bufferDataSize = dataSizeForIndex(i) * m_numParticles * sizeof(float);
|
||||||
|
|
||||||
glEnableVertexAttribArray(i);
|
glEnableVertexAttribArray(i);
|
||||||
|
@ -130,16 +140,14 @@ namespace endofthejedi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleBatch::render()
|
void ParticleBatch::render(Shader *shader)
|
||||||
{
|
{
|
||||||
//std::cout<<"[ParticleBatch] render " << std::endl;
|
//std::cout<<"[ParticleBatch] render " << std::endl;
|
||||||
m_shader.bind();
|
glUniform1f(shader->location("age"), m_age);
|
||||||
|
glUniform1f(shader->location("maxVelocity"), m_maxVelocity);
|
||||||
glUniform1f(m_shader.location("age"), m_age);
|
glUniform1f(shader->location("halfAge"), m_halfAge);
|
||||||
glUniform1f(m_shader.location("maxVelocity"), m_maxVelocity);
|
glUniform1f(shader->location("size"), m_particleRadius);
|
||||||
glUniform1f(m_shader.location("halfAge"), m_halfAge);
|
glUniform3f(shader->location("explCenter"), m_center.x, m_center.y, m_center.z);
|
||||||
glUniform1f(m_shader.location("size"), m_particleRadius);
|
|
||||||
glUniform3f(m_shader.location("explCenter"), m_center.x, m_center.y, m_center.z);
|
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
|
@ -154,7 +162,7 @@ namespace endofthejedi {
|
||||||
#if 0
|
#if 0
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
for (size_t index=0; index<m_numParticles; index++) {
|
for (size_t index=0; index<m_numParticles; index++) {
|
||||||
for (int i=0; i<4; i++) {
|
for (size_t i=0; i<4; i++) {
|
||||||
glm::vec2 p = m_data_position[index] + triangles[i];
|
glm::vec2 p = m_data_position[index] + triangles[i];
|
||||||
//glColor3f(1.0, 0.0, 0.0);
|
//glColor3f(1.0, 0.0, 0.0);
|
||||||
glVertex2f(p.x, p.y);
|
glVertex2f(p.x, p.y);
|
||||||
|
@ -165,9 +173,9 @@ namespace endofthejedi {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ParticleBatch::dataSizeForIndex(int i)
|
size_t ParticleBatch::dataSizeForIndex(size_t index)
|
||||||
{
|
{
|
||||||
switch(i) {
|
switch(index) {
|
||||||
case 0:
|
case 0:
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
@ -176,25 +184,23 @@ namespace endofthejedi {
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "bad" << std::endl;
|
std::cerr << "dataSizeForIndex() bad" << std::endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ParticleBatch::dataSourceForIndex(int i)
|
void *ParticleBatch::dataSourceForIndex(size_t index)
|
||||||
{
|
{
|
||||||
switch(i) {
|
switch(index) {
|
||||||
case 0: return (void *) m_data_quad.data();
|
case 0: return (void *) m_data_geometry.data();
|
||||||
case 1: return (void *) m_data_position.data();
|
case 1: return (void *) m_data_position.data();
|
||||||
case 2: return (void *) m_data_velocity.data();
|
case 2: return (void *) m_data_velocity.data();
|
||||||
case 3: return (void *) m_data_kind.data();
|
case 3: return (void *) m_data_max_distance.data();
|
||||||
case 4: return (void *) m_data_max_age.data();
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "bad" << std::endl;
|
std::cerr << "dataSourceForIndex() bad" << std::endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +212,6 @@ namespace endofthejedi {
|
||||||
|
|
||||||
bool ParticleBatch::done() const
|
bool ParticleBatch::done() const
|
||||||
{
|
{
|
||||||
return m_age >= 5.0*m_halfAge;
|
return m_age >= m_maxNumHalfAges*m_halfAge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,39 @@
|
||||||
#include "glclasses.hpp"
|
#include "glclasses.hpp"
|
||||||
|
|
||||||
namespace endofthejedi {
|
namespace endofthejedi {
|
||||||
|
#if 0
|
||||||
|
class VertexAttribute {
|
||||||
|
public:
|
||||||
|
class Data {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Integer, Float, Float2, Float3, Float4, Matrix3, Matrix4
|
||||||
|
};
|
||||||
|
|
||||||
|
void setDataInteger(int index, int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Data(Type type, int size) : m_type(type), m_size(size)
|
||||||
|
{
|
||||||
|
if (type ==
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_size;
|
||||||
|
Type m_type;
|
||||||
|
std::vector<int> m_sourceInteger;
|
||||||
|
std::vector<float> m_sourceFloat;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Data data;
|
||||||
|
std::string variableName;
|
||||||
|
int divisor;
|
||||||
|
GLint index;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class ParticleBatch {
|
class ParticleBatch {
|
||||||
public:
|
public:
|
||||||
ParticleBatch(size_t id, size_t numParticles, float particleRadius, float halfAge);
|
ParticleBatch(size_t id, size_t numParticles, float particleRadius, float halfAge);
|
||||||
|
@ -15,47 +48,58 @@ namespace endofthejedi {
|
||||||
// deallocate opengl stuff on destroy
|
// deallocate opengl stuff on destroy
|
||||||
~ParticleBatch();
|
~ParticleBatch();
|
||||||
|
|
||||||
|
// set particle data
|
||||||
|
void setParticle(size_t index, const glm::vec3 &p, const glm::vec3 &v, float maxDistance);
|
||||||
|
|
||||||
|
// stuff for setup/rendering usage
|
||||||
|
void setup(Shader *shader);
|
||||||
|
void bind();
|
||||||
|
void upload();
|
||||||
|
void render(Shader *shader);
|
||||||
|
|
||||||
|
// advance internal state (mostly age)
|
||||||
|
void tick(float dt);
|
||||||
|
|
||||||
|
// check if the lifetime is over and whether it can be deleted.
|
||||||
|
bool done() const;
|
||||||
|
|
||||||
|
// access attributes
|
||||||
size_t numParticles() const { return m_numParticles; }
|
size_t numParticles() const { return m_numParticles; }
|
||||||
|
float ageNormalized() const { return m_age / (m_maxNumHalfAges*m_halfAge); }
|
||||||
|
float age() const { return m_age; }
|
||||||
|
size_t id() const { return m_id; }
|
||||||
|
const glm::vec3 &explosionCenter() const { return m_center; }
|
||||||
|
|
||||||
void setParticle(size_t index, const glm::vec3 &p, const glm::vec3 &v);
|
// set attributes
|
||||||
|
|
||||||
void setCenter(const glm::vec3 ¢er);
|
void setCenter(const glm::vec3 ¢er);
|
||||||
void setMaxVelocity(float maxVelocity);
|
void setMaxVelocity(float maxVelocity);
|
||||||
|
|
||||||
void bind();
|
private:
|
||||||
void upload();
|
size_t dataSizeForIndex(size_t index);
|
||||||
void render();
|
void *dataSourceForIndex(size_t index);
|
||||||
|
|
||||||
void tick(float dt);
|
|
||||||
bool done() const;
|
|
||||||
|
|
||||||
Shader *shader() { return &m_shader; }
|
|
||||||
|
|
||||||
size_t id() const { return m_id; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t dataSizeForIndex(int i);
|
|
||||||
void *dataSourceForIndex(int i);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// id of explosion
|
||||||
size_t m_id;
|
size_t m_id;
|
||||||
|
|
||||||
|
// uniforms for the shader
|
||||||
size_t m_numParticles;
|
size_t m_numParticles;
|
||||||
float m_particleRadius;
|
float m_particleRadius;
|
||||||
const float m_halfAge;
|
|
||||||
float m_age;
|
float m_age;
|
||||||
|
const float m_halfAge;
|
||||||
|
const float m_maxNumHalfAges;
|
||||||
float m_maxVelocity;
|
float m_maxVelocity;
|
||||||
glm::vec3 m_center;
|
glm::vec3 m_center;
|
||||||
|
|
||||||
GLuint m_data_vbos[5];
|
// meta data
|
||||||
|
size_t m_num_vertex_buffers;
|
||||||
|
std::vector<GLuint> m_data_vbos;
|
||||||
|
std::vector<GLuint> m_attr_locations;
|
||||||
|
|
||||||
std::vector<float> m_data_quad;
|
// vertex attributes
|
||||||
|
std::vector<float> m_data_geometry;
|
||||||
std::vector<glm::vec3> m_data_position;
|
std::vector<glm::vec3> m_data_position;
|
||||||
std::vector<glm::vec3> m_data_velocity;
|
std::vector<glm::vec3> m_data_velocity;
|
||||||
std::vector<float> m_data_kind;
|
std::vector<float> m_data_max_distance;
|
||||||
std::vector<float> m_data_max_age;
|
|
||||||
|
|
||||||
GLuint m_attr_locations[5];
|
|
||||||
|
|
||||||
Shader m_shader;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include "state/events/explosion_event.hpp"
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include "state/events/missile_event.hpp"
|
||||||
#include <glm/gtx/euler_angles.hpp>
|
#include "state/events/ship_event.hpp"
|
||||||
#include <glm/gtc/random.hpp>
|
|
||||||
|
#include "developer_console.hpp"
|
||||||
|
|
||||||
namespace endofthejedi {
|
namespace endofthejedi {
|
||||||
void RendererPolygon3d::setup()
|
void RendererPolygon3d::setup()
|
||||||
|
@ -14,23 +15,96 @@ namespace endofthejedi {
|
||||||
|
|
||||||
std::cout<<"setup polygon 3d" << std::endl;
|
std::cout<<"setup polygon 3d" << std::endl;
|
||||||
|
|
||||||
m_shader.init();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
std::string vss_simple = "../data/shader/simple.vert";
|
|
||||||
std::string fss_simple = "../data/shader/simple.frag";
|
|
||||||
m_shader.loadFile(vss_simple, GL_VERTEX_SHADER);
|
|
||||||
m_shader.loadFile(fss_simple, GL_FRAGMENT_SHADER);
|
|
||||||
#else
|
|
||||||
std::string vss_game_objects = "../data/shader/gameobjects.vert";
|
std::string vss_game_objects = "../data/shader/gameobjects.vert";
|
||||||
std::string fss_game_objects = "../data/shader/gameobjects.frag";
|
std::string fss_game_objects = "../data/shader/gameobjects.frag";
|
||||||
m_shader.loadFile(vss_game_objects, GL_VERTEX_SHADER);
|
|
||||||
m_shader.loadFile(fss_game_objects, GL_FRAGMENT_SHADER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
addModel("../data/mesh/small_atomic_bomb.stl", &m_missileModel);
|
m_shader_game_objects.init();
|
||||||
addModel("../data/mesh/planet_12.stl", &m_planetModel);
|
m_shader_game_objects.loadFile(vss_game_objects, GL_VERTEX_SHADER);
|
||||||
|
m_shader_game_objects.loadFile(fss_game_objects, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
std::string vss_particles = "../data/shader/particle.vert";
|
||||||
|
std::string fss_particles = "../data/shader/particle.frag";
|
||||||
|
|
||||||
|
m_shader_particles.init();
|
||||||
|
m_shader_particles.loadFile(vss_particles, GL_VERTEX_SHADER);
|
||||||
|
m_shader_particles.loadFile(fss_particles, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
std::string vss_background = "../data/shader/background.vert";
|
||||||
|
std::string fss_background = "../data/shader/background.frag";
|
||||||
|
|
||||||
|
m_shader_background.init();
|
||||||
|
m_shader_background.loadFile(vss_background, GL_VERTEX_SHADER);
|
||||||
|
m_shader_background.loadFile(fss_background, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
//addModel("../data/mesh/small_atomic_bomb.stl", &m_missileModel);
|
||||||
|
addModel("../data/mesh/rocket.stl", &m_missileModel);
|
||||||
|
addModel("../data/mesh/planet_128.stl", &m_planetModel);
|
||||||
addModel("../data/mesh/ship_ufo.stl", &m_shipModel);
|
addModel("../data/mesh/ship_ufo.stl", &m_shipModel);
|
||||||
|
|
||||||
|
m_texture = nullptr;
|
||||||
|
m_backgroundTexturePath = "../data/img/test.png";
|
||||||
|
loadBackgroundTexture();
|
||||||
|
|
||||||
|
developer::DeveloperConsole::instance().addCallback("reload_bg", [=](const std::string &)
|
||||||
|
{
|
||||||
|
loadBackgroundTexture();
|
||||||
|
return developer::resultOkay();
|
||||||
|
});
|
||||||
|
|
||||||
|
developer::DeveloperConsole::instance().addCallback("set_bg", [=](const std::string &str)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
std::string rest;
|
||||||
|
util::splitIntoTokenAndRest(str, token, rest);
|
||||||
|
|
||||||
|
m_backgroundTexturePath = token;
|
||||||
|
loadBackgroundTexture();
|
||||||
|
return developer::resultOkay();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererPolygon3d::loadBackgroundTexture()
|
||||||
|
{
|
||||||
|
//m_texture = new ImageTexture("../data/img/test.png");
|
||||||
|
if (m_texture != nullptr) {
|
||||||
|
delete(m_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
//"../data/img/stars_nebular.png");
|
||||||
|
m_texture = new ImageTexture(m_backgroundTexturePath);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_texture->loadPng();
|
||||||
|
|
||||||
|
std::cout<<"texture loading: " << m_texture->valid() << std::endl;
|
||||||
|
if (!m_texture->valid()) {
|
||||||
|
std::cout<<"loading failed!";
|
||||||
|
return;
|
||||||
|
//exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 s = m_texture->size();
|
||||||
|
std::cout<<"texture size is " << s.x << " X " << s.y << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererPolygon3d::renderBackgroundImage()
|
||||||
|
{
|
||||||
|
m_shader_background.bind();
|
||||||
|
|
||||||
|
glUniform2fv(m_shader_background.location("uvScale"), 1, glm::value_ptr(m_texture->uvScale()));
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_texture->textureId());
|
||||||
|
|
||||||
|
//drawNdcQuad();
|
||||||
|
glColor3f(1.0, 0.0, 0.0);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glVertex2f(-1.0f, -1.0f);
|
||||||
|
glVertex2f(1.0f, -1.0f);
|
||||||
|
glVertex2f(1.0f, 1.0f);
|
||||||
|
glVertex2f(-1.0f, 1.0f);
|
||||||
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererPolygon3d::render(const game::State *state)
|
void RendererPolygon3d::render(const game::State *state)
|
||||||
|
@ -52,20 +126,28 @@ namespace endofthejedi {
|
||||||
// TODO: add little rocks flying around
|
// TODO: add little rocks flying around
|
||||||
|
|
||||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
//float s = 0.1;
|
|
||||||
//glClearColor(s, s, s, 1.0);
|
|
||||||
|
|
||||||
m_shader.bind();
|
renderBackgroundImage();
|
||||||
|
|
||||||
|
//float s = 0.1;
|
||||||
|
//glClearColor(s, s, 1.2*s, 1.0);
|
||||||
|
|
||||||
|
m_shader_game_objects.bind();
|
||||||
|
|
||||||
// TODO: add ONE sun planet
|
// TODO: add ONE sun planet
|
||||||
// TODO: add lights for explosions
|
// TODO: add lights for explosions
|
||||||
|
|
||||||
configureLightningInShader();
|
configureLightningInShader(&m_shader_game_objects);
|
||||||
|
|
||||||
|
//std::cout<<"setting aspect ratio: " << m_aspectRatio << std::endl;
|
||||||
|
glUniform1f(m_shader_game_objects.location("aspectRatio"), m_aspectRatio);
|
||||||
|
|
||||||
renderPlanets();
|
renderPlanets();
|
||||||
renderShips();
|
renderShips();
|
||||||
renderMissiles();
|
renderMissiles();
|
||||||
|
|
||||||
renderParticles();
|
renderParticles();
|
||||||
|
|
||||||
renderTraces();
|
renderTraces();
|
||||||
|
|
||||||
//glColor3f(1.0, 0.0, 0.0);
|
//glColor3f(1.0, 0.0, 0.0);
|
||||||
|
@ -81,17 +163,24 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void RendererPolygon3d::renderParticles()
|
void RendererPolygon3d::renderParticles()
|
||||||
{
|
{
|
||||||
|
m_shader_particles.bind();
|
||||||
|
|
||||||
|
glUniform1f(m_shader_particles.location("aspectRatio"), m_aspectRatio);
|
||||||
|
|
||||||
for (ParticleBatch *batch : m_particles) {
|
for (ParticleBatch *batch : m_particles) {
|
||||||
batch->bind();
|
batch->bind();
|
||||||
batch->render();
|
batch->render(&m_shader_particles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererPolygon3d::addExplosionEffect(size_t id, const glm::vec2 &pos, size_t n, float duration)
|
void RendererPolygon3d::addExplosionEffect(
|
||||||
|
size_t id, const glm::vec2 &explCenter, const glm::vec2 &missileVelocity,
|
||||||
|
bool isPlanetHit,
|
||||||
|
size_t n, float duration)
|
||||||
{
|
{
|
||||||
//float particleRadius = 0.005;
|
//float particleRadius = 0.005;
|
||||||
//float particleRadius = 0.003;
|
//float particleRadius = 0.003;
|
||||||
float particleRadius = 0.005;
|
float particleRadius = 0.02;
|
||||||
|
|
||||||
// TODO: use this as shader input too and make the area 2x around this
|
// TODO: use this as shader input too and make the area 2x around this
|
||||||
// so that it stays hot/yellow for 2/3 of the time
|
// so that it stays hot/yellow for 2/3 of the time
|
||||||
|
@ -99,7 +188,8 @@ namespace endofthejedi {
|
||||||
float maxVelocity = 0.4f;
|
float maxVelocity = 0.4f;
|
||||||
|
|
||||||
ParticleBatch *batch = new ParticleBatch(id, n, particleRadius, duration);
|
ParticleBatch *batch = new ParticleBatch(id, n, particleRadius, duration);
|
||||||
batch->setCenter(glm::vec3(pos, 0.0));
|
batch->setup(&m_shader_particles);
|
||||||
|
batch->setCenter(glm::vec3(explCenter, 0.0));
|
||||||
batch->setMaxVelocity(maxVelocity);
|
batch->setMaxVelocity(maxVelocity);
|
||||||
|
|
||||||
for (size_t i=0; i<n; i++) {
|
for (size_t i=0; i<n; i++) {
|
||||||
|
@ -113,10 +203,123 @@ namespace endofthejedi {
|
||||||
// especially in 3d this would look bad without 3d velocity vector.
|
// especially in 3d this would look bad without 3d velocity vector.
|
||||||
//glm::vec3 v = 0.5f*glm::vec3(sin(t), cos(t), util::randf_m1_1());
|
//glm::vec3 v = 0.5f*glm::vec3(sin(t), cos(t), util::randf_m1_1());
|
||||||
|
|
||||||
glm::vec3 v = glm::ballRand(maxVelocity);
|
glm::vec3 pos = glm::vec3(explCenter, 0.0) + glm::ballRand(explCoreSize);
|
||||||
v *= util::randf_0_1() * util::randf_0_1() * util::randf_0_1();
|
|
||||||
|
|
||||||
batch->setParticle(i, glm::vec3(pos, 0.0) + glm::ballRand(explCoreSize), v);
|
glm::vec3 v = glm::ballRand(maxVelocity);
|
||||||
|
|
||||||
|
// TODO: is that good?
|
||||||
|
if (isPlanetHit) {
|
||||||
|
v *= util::randf_0_1() * util::randf_0_1() * util::randf_0_1();
|
||||||
|
} else {
|
||||||
|
v *= util::randf_0_1();
|
||||||
|
}
|
||||||
|
|
||||||
|
// find collisions with planetns and limit max distance so particles
|
||||||
|
// won't fly through planets
|
||||||
|
//float maxDist = 0.1;
|
||||||
|
//float maxDist = 0.1*util::randf_0_1();
|
||||||
|
bool isInsidePlanet = false;
|
||||||
|
float maxParticleDist = INFINITY;
|
||||||
|
|
||||||
|
const game::Planet *nearestPlanet = nullptr;
|
||||||
|
for (const game::Planet *planet : m_state->planets) {
|
||||||
|
const glm::vec3 ppos3 = glm::vec3(planet->position, 0.0f);
|
||||||
|
|
||||||
|
// TODO: that's slightly wrong. use intersection for this.
|
||||||
|
float dist = glm::distance(ppos3, pos);
|
||||||
|
if (dist <= planet->radius) {
|
||||||
|
isInsidePlanet = true;
|
||||||
|
nearestPlanet = planet;
|
||||||
|
}
|
||||||
|
if (isInsidePlanet) {
|
||||||
|
// skip searching for nearer planets once we are inside some
|
||||||
|
// planet as the position/velocity will be changed to start
|
||||||
|
// at the surface of the planet we were in with
|
||||||
|
// reflected or planet-normal velocity.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO: if inside, move position so that it looks like
|
||||||
|
// reflecting the particle from the planet
|
||||||
|
bool fliesInPlanetDirection = glm::dot(v, ppos3-pos) > 0.0f;
|
||||||
|
if (dist < maxParticleDist && fliesInPlanetDirection) {
|
||||||
|
nearestPlanet = planet;
|
||||||
|
maxParticleDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool makeStationary = false;
|
||||||
|
|
||||||
|
if (isInsidePlanet && isPlanetHit) {
|
||||||
|
util::IntersectionTest intersect;
|
||||||
|
if (!intersect.raySphere(
|
||||||
|
glm::vec3(explCenter, 0.0f), v,
|
||||||
|
glm::vec3(nearestPlanet->position, 0.0f), nearestPlanet->radius))
|
||||||
|
{
|
||||||
|
makeStationary = true;
|
||||||
|
//std::cout<<"warning: intersection should be valid!" << std::endl;
|
||||||
|
// TODO: must be as they lie on a plane and the dist is < as
|
||||||
|
// the radius.
|
||||||
|
// handle if this is wrong.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// simple reflection, ignoring the missile velocity: this looks good enough
|
||||||
|
(void) missileVelocity;
|
||||||
|
glm::vec3 planetNormal = glm::normalize(pos - glm::vec3(nearestPlanet->position, 0.0f));
|
||||||
|
v = glm::length(v) * planetNormal;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// considering the missile velocity is not yet working:
|
||||||
|
|
||||||
|
// set position to the intersection point between explosion
|
||||||
|
// center and planet surface
|
||||||
|
//pos = intersect.pointAtDistance(intersect.distance());
|
||||||
|
//v = glm::vec3(missileVelocity, 0.0f);
|
||||||
|
//v = v - 2.0f*glm::dot(v, planetNormal) * planetNormal;
|
||||||
|
//v *= 4.0;
|
||||||
|
//maxParticleDist = 100.0;
|
||||||
|
//v = -v;
|
||||||
|
|
||||||
|
//pos = glm::vec3(nearestPlanet->position, 0.0f) + nearestPlanet->radius*planetNormal;
|
||||||
|
|
||||||
|
// set position to the intersection point between explosion
|
||||||
|
// center and planet surface
|
||||||
|
//const glm::vec3 planetNormal = glm::vec3(glm::normalize(explCenter - nearestPlanet->position), 0.0f);
|
||||||
|
|
||||||
|
//pos = glm::vec3(nearestPlanet->position, 0.0f) + nearestPlanet->radius*planetNormal;
|
||||||
|
|
||||||
|
// build new velocity by reflecting the old velocity on the
|
||||||
|
// planet normal
|
||||||
|
// TODO: add a bit random
|
||||||
|
// TODO: add reflection
|
||||||
|
// TODO: distribute particles around main reflection angle and
|
||||||
|
// TODO: add material exhaust that is specific for the planet.
|
||||||
|
// TODO: spawn waves on water planet
|
||||||
|
// TODO: start fire on gas planet
|
||||||
|
//v = glm::length(v) * planetNormal;
|
||||||
|
//v = v - 2.0f*glm::dot(v, planetNormal) * planetNormal;
|
||||||
|
//v = glm::length(v) * planetNormal;
|
||||||
|
|
||||||
|
//glm::vec3 r = v - 2.0f*glm::dot(v, planetNormal) * planetNormal;
|
||||||
|
//glm::vec3 vn = glm::length(v) * planetNormal;
|
||||||
|
//v = (r+vn) / 2.0f;
|
||||||
|
|
||||||
|
//glm::vec3 vc = glm::vec3(nearestPlanet->position-explCenter, 0.0f);
|
||||||
|
//glm::vec3 r = vc - 2.0f*glm::dot(vc, planetNormal) * planetNormal;
|
||||||
|
//v = r;
|
||||||
|
}
|
||||||
|
} else if (isInsidePlanet && !isPlanetHit) {
|
||||||
|
// if a planet is just hit by explosions particles but not the
|
||||||
|
// missile itself, don't reflect the particles in the planet.
|
||||||
|
// just set them as stationary at place of explosion
|
||||||
|
makeStationary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (makeStationary) {
|
||||||
|
v = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
pos = glm::vec3(explCenter, 0.0f);;
|
||||||
|
}
|
||||||
|
|
||||||
|
batch->setParticle(i, pos, v, maxParticleDist);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch->upload();
|
batch->upload();
|
||||||
|
@ -126,6 +329,7 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void RendererPolygon3d::advanceGraphicObjects(float dt)
|
void RendererPolygon3d::advanceGraphicObjects(float dt)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
for (const game::Explosion *expl : m_state->explosions) {
|
for (const game::Explosion *expl : m_state->explosions) {
|
||||||
bool gotIt = false;
|
bool gotIt = false;
|
||||||
for (ParticleBatch *batch : m_particles) {
|
for (ParticleBatch *batch : m_particles) {
|
||||||
|
@ -136,12 +340,61 @@ namespace endofthejedi {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gotIt) {
|
if (!gotIt) {
|
||||||
addExplosionEffect(expl->id, expl->position, 1000, 1.0);
|
addExplosionEffect(
|
||||||
|
expl->id, expl->position,
|
||||||
|
expl->missileVelocity,
|
||||||
|
(expl->hit == game::Hit::Planet),
|
||||||
|
1000, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto *evt : m_state->currentStateUpdateEvents()) {
|
||||||
|
auto type = evt->eventType();
|
||||||
|
auto cycle = evt->lifeCycle();
|
||||||
|
|
||||||
|
if (type == game::EventType::Explosion) {
|
||||||
|
if (cycle == game::LifeCycle::Create) {
|
||||||
|
game::ExplosionEvent *ee = static_cast<game::ExplosionEvent*>(evt);
|
||||||
|
game::Explosion *expl = static_cast<game::Explosion*>(ee->object());
|
||||||
|
|
||||||
|
addExplosionEffect(
|
||||||
|
expl->id, expl->position,
|
||||||
|
expl->missileVelocity,
|
||||||
|
(expl->hit == game::Hit::Planet),
|
||||||
|
1000, 1.0);
|
||||||
|
}
|
||||||
|
} else if (type == game::EventType::Ship) {
|
||||||
|
game::ShipEvent *me = static_cast<game::ShipEvent*>(evt);
|
||||||
|
game::Ship *ship = static_cast<game::Ship*>(me->object());
|
||||||
|
|
||||||
|
// is always modificated
|
||||||
|
if (cycle == game::LifeCycle::Create) {
|
||||||
|
//std::cout<<"[renderer] adding missile #" << missile->id << std::endl;
|
||||||
|
m_ships.push_back(ship);
|
||||||
|
|
||||||
|
} else if (cycle == game::LifeCycle::Destroy) {
|
||||||
|
//std::cout<<"[renderer] removing missile #" << missile->id << std::endl;
|
||||||
|
m_ships.remove(ship);
|
||||||
|
}
|
||||||
|
} else if (type == game::EventType::Missile) {
|
||||||
|
game::MissileEvent *me = static_cast<game::MissileEvent*>(evt);
|
||||||
|
game::Missile *missile = static_cast<game::Missile*>(me->object());
|
||||||
|
|
||||||
|
// is always modificated
|
||||||
|
if (cycle == game::LifeCycle::Create) {
|
||||||
|
//std::cout<<"[renderer] adding missile #" << missile->id << std::endl;
|
||||||
|
m_missiles.push_back(missile);
|
||||||
|
|
||||||
|
} else if (cycle == game::LifeCycle::Destroy) {
|
||||||
|
//std::cout<<"[renderer] removing missile #" << missile->id << std::endl;
|
||||||
|
m_missiles.remove(missile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (m_particles.size() == 0) {
|
//if (m_particles.size() == 0) {
|
||||||
// addExplosionEffect(0, glm::vec2(0.0, 0.0), 1000, 2.0);
|
// addExplosionEffect(0, glm::vec2(0.0, 0.0), glm::vec2(0.0, 0.0), false, 10000, 2.0);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
std::vector<ParticleBatch*> rm;
|
std::vector<ParticleBatch*> rm;
|
||||||
|
@ -167,12 +420,12 @@ namespace endofthejedi {
|
||||||
// too (same for missiles)
|
// too (same for missiles)
|
||||||
for (const game::Planet *planet : m_state->planets) {
|
for (const game::Planet *planet : m_state->planets) {
|
||||||
glm::mat4 model = computeModelMatrix(planet);
|
glm::mat4 model = computeModelMatrix(planet);
|
||||||
glUniformMatrix4fv(m_shader.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
glUniformMatrix4fv(m_shader_game_objects.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
||||||
|
|
||||||
glm::vec3 c = planet->getColor();
|
glm::vec3 c = planet->getColor();
|
||||||
glUniform3f(m_shader.location("materialColor"), c.x, c.y, c.z);
|
glUniform3f(m_shader_game_objects.location("materialColor"), c.x, c.y, c.z);
|
||||||
glUniform1i(m_shader.location("materialSeed"), planet->seed);
|
glUniform1i(m_shader_game_objects.location("materialSeed"), planet->seed);
|
||||||
glUniform1i(m_shader.location("materialKind"), (int) planet->material);
|
glUniform1i(m_shader_game_objects.location("materialKind"), (int) planet->material);
|
||||||
|
|
||||||
m_planetModel->render();
|
m_planetModel->render();
|
||||||
}
|
}
|
||||||
|
@ -180,31 +433,33 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void RendererPolygon3d::renderMissiles()
|
void RendererPolygon3d::renderMissiles()
|
||||||
{
|
{
|
||||||
|
// TODO: add fire trail for missiles near the sun
|
||||||
|
|
||||||
m_missileModel->bind();
|
m_missileModel->bind();
|
||||||
|
|
||||||
for (const game::Player *player : m_state->players) {
|
for (const game::Missile *missile : m_missiles) {
|
||||||
for (const game::Missile *missile : player->missiles) {
|
|
||||||
glm::vec3 c = glm::vec3(1.0, 1.0, 0.3);
|
glm::vec3 c = glm::vec3(1.0, 1.0, 0.3);
|
||||||
glUniform3f(m_shader.location("materialColor"), c.x, c.y, c.z);
|
glUniform3f(m_shader_game_objects.location("materialColor"), c.x, c.y, c.z);
|
||||||
|
|
||||||
|
// TODO: rename functions so their name represents what args they
|
||||||
|
// take
|
||||||
glm::mat4 model = computeModelMatrix(missile);
|
glm::mat4 model = computeModelMatrix(missile);
|
||||||
glUniformMatrix4fv(m_shader.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
glUniformMatrix4fv(m_shader_game_objects.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
||||||
|
|
||||||
m_missileModel->render();
|
m_missileModel->render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RendererPolygon3d::renderShips()
|
void RendererPolygon3d::renderShips()
|
||||||
{
|
{
|
||||||
m_shipModel->bind();
|
m_shipModel->bind();
|
||||||
|
|
||||||
for (const game::Ship *ship : m_state->ships) {
|
for (const game::Ship *ship : m_ships) {
|
||||||
glm::mat4 model = computeModelMatrix(ship);
|
glm::mat4 model = computeModelMatrix(ship);
|
||||||
glUniformMatrix4fv(m_shader.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
glUniformMatrix4fv(m_shader_game_objects.location("model"), 1, GL_FALSE, glm::value_ptr(model));
|
||||||
|
|
||||||
glm::vec3 c = glm::vec3(0.1, 1.0, 0.2);
|
glm::vec3 c = glm::vec3(0.1, 1.0, 0.2);
|
||||||
glUniform3f(m_shader.location("materialColor"), c.x, c.y, c.z);
|
glUniform3f(m_shader_game_objects.location("materialColor"), c.x, c.y, c.z);
|
||||||
|
|
||||||
m_shipModel->render();
|
m_shipModel->render();
|
||||||
}
|
}
|
||||||
|
@ -220,7 +475,7 @@ namespace endofthejedi {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*dest)->setup(&m_shader);
|
(*dest)->setup(&m_shader_game_objects);
|
||||||
(*dest)->uploadToOpenGl();
|
(*dest)->uploadToOpenGl();
|
||||||
|
|
||||||
m_models.push_back(*dest);
|
m_models.push_back(*dest);
|
||||||
|
@ -236,9 +491,17 @@ namespace endofthejedi {
|
||||||
glm::vec2 vn = glm::normalize(missile->velocity);
|
glm::vec2 vn = glm::normalize(missile->velocity);
|
||||||
float a = std::atan2(vn.y, vn.x);
|
float a = std::atan2(vn.y, vn.x);
|
||||||
|
|
||||||
|
glm::mat4 mat = computeModelMatrix(missile->position, 0.1f, a);
|
||||||
|
|
||||||
// TODO: which visual size has the rocket? in game its just a point with
|
// TODO: which visual size has the rocket? in game its just a point with
|
||||||
// no size because all others have size.
|
// no size because all others have size.
|
||||||
return computeModelMatrix(missile->position, 0.03f, a);
|
//for atomic bomb
|
||||||
|
//return computeModelMatrix(missile->position, 0.03f, a);
|
||||||
|
|
||||||
|
// flipped too
|
||||||
|
mat = glm::rotate(mat, (float) M_PI/2.0f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 RendererPolygon3d::computeModelMatrix(const game::Ship *ship)
|
glm::mat4 RendererPolygon3d::computeModelMatrix(const game::Ship *ship)
|
||||||
|
@ -293,7 +556,7 @@ namespace endofthejedi {
|
||||||
glPolygonMode(GL_FRONT, GL_FILL);
|
glPolygonMode(GL_FRONT, GL_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererPolygon3d::configureLightningInShader()
|
void RendererPolygon3d::configureLightningInShader(Shader *shader) const
|
||||||
{
|
{
|
||||||
// TODO: add a few small lights for explosions so they lit the
|
// TODO: add a few small lights for explosions so they lit the
|
||||||
// surroundsings
|
// surroundsings
|
||||||
|
@ -310,7 +573,49 @@ namespace endofthejedi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glUniform3f(m_shader.location("lightPosition"), p.x, p.y, p.z);
|
glUniform3f(shader->location("lightPosition"), p.x, p.y, p.z);
|
||||||
glUniform3f(m_shader.location("lightColor"), c.x, c.y, c.z);
|
glUniform3f(shader->location("lightColor"), c.x, c.y, c.z);
|
||||||
|
|
||||||
|
std::vector<glm::vec3> positions;
|
||||||
|
std::vector<float> intensities;
|
||||||
|
|
||||||
|
size_t numExplLights = 0;
|
||||||
|
|
||||||
|
for (ParticleBatch *batch : m_particles) {
|
||||||
|
float age = batch->ageNormalized();
|
||||||
|
// TODO: use function with a peak for this:
|
||||||
|
//
|
||||||
|
// /\__
|
||||||
|
// _/ \--____
|
||||||
|
|
||||||
|
float intensity = 1.0-age;
|
||||||
|
glm::vec3 p = batch->explosionCenter();
|
||||||
|
|
||||||
|
intensities.push_back(intensity);
|
||||||
|
positions.push_back(p);
|
||||||
|
|
||||||
|
numExplLights++;
|
||||||
|
|
||||||
|
if (numExplLights == 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glUniform1i( shader->location("explLightsNum"), numExplLights);
|
||||||
|
|
||||||
|
if (numExplLights != 0) {
|
||||||
|
glUniform3fv(shader->location("explLightsPos"), numExplLights, glm::value_ptr(positions[0]));
|
||||||
|
glUniform1fv(shader->location("explLightsIntensities"), numExplLights, intensities.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererPolygon3d::setWindowSize(int px, int py)
|
||||||
|
{
|
||||||
|
m_aspectRatio = (float) px / (float) py;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererPolygon3d::setCameraMatrix(const glm::mat4 &cam)
|
||||||
|
{
|
||||||
|
(void) cam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
|
#include <glm/gtc/random.hpp>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
#include "glclasses.hpp"
|
#include "glclasses.hpp"
|
||||||
|
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
|
@ -16,9 +23,7 @@
|
||||||
|
|
||||||
#include "particle_batch.hpp"
|
#include "particle_batch.hpp"
|
||||||
#include "polygon_model.hpp"
|
#include "polygon_model.hpp"
|
||||||
|
#include "image_texture.hpp"
|
||||||
#include <glm/vec3.hpp>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
namespace endofthejedi {
|
namespace endofthejedi {
|
||||||
|
|
||||||
|
@ -27,6 +32,9 @@ namespace endofthejedi {
|
||||||
void setup();
|
void setup();
|
||||||
void render(const game::State *state) override;
|
void render(const game::State *state) override;
|
||||||
|
|
||||||
|
void setWindowSize(int px, int py);
|
||||||
|
void setCameraMatrix(const glm::mat4 &cam);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderPlanets();
|
void renderPlanets();
|
||||||
void renderMissiles();
|
void renderMissiles();
|
||||||
|
@ -35,7 +43,10 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void addModel(const std::string &filename, PolygonModel **dest);
|
void addModel(const std::string &filename, PolygonModel **dest);
|
||||||
|
|
||||||
void addExplosionEffect(size_t id, const glm::vec2 &pos, size_t n, float duration);
|
void addExplosionEffect(
|
||||||
|
size_t id, const glm::vec2 &pos, const glm::vec2 &missileVelocity,
|
||||||
|
bool hitPlanet,
|
||||||
|
size_t n, float duration);
|
||||||
|
|
||||||
void advanceGraphicObjects(float dt);
|
void advanceGraphicObjects(float dt);
|
||||||
|
|
||||||
|
@ -49,7 +60,11 @@ namespace endofthejedi {
|
||||||
|
|
||||||
void renderTraces();
|
void renderTraces();
|
||||||
|
|
||||||
void configureLightningInShader();
|
void configureLightningInShader(Shader *shader) const;
|
||||||
|
|
||||||
|
void renderBackgroundImage();
|
||||||
|
|
||||||
|
void loadBackgroundTexture();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// all models are also here (for easy reloading etc.)
|
// all models are also here (for easy reloading etc.)
|
||||||
|
@ -61,7 +76,9 @@ namespace endofthejedi {
|
||||||
PolygonModel *m_shipModel;
|
PolygonModel *m_shipModel;
|
||||||
|
|
||||||
// for rendering everything
|
// for rendering everything
|
||||||
Shader m_shader;
|
Shader m_shader_background;
|
||||||
|
Shader m_shader_game_objects;
|
||||||
|
Shader m_shader_particles;
|
||||||
|
|
||||||
// for accessing
|
// for accessing
|
||||||
const game::State *m_state;
|
const game::State *m_state;
|
||||||
|
@ -70,5 +87,14 @@ namespace endofthejedi {
|
||||||
|
|
||||||
// time value for last rendering cycle (-1 after setup/startup)
|
// time value for last rendering cycle (-1 after setup/startup)
|
||||||
float m_lastTime;
|
float m_lastTime;
|
||||||
|
|
||||||
|
float m_aspectRatio;
|
||||||
|
|
||||||
|
// TODO: put representation specialized for rendering in here
|
||||||
|
std::list<const game::Missile*> m_missiles;
|
||||||
|
std::list<const game::Ship*> m_ships;
|
||||||
|
|
||||||
|
std::string m_backgroundTexturePath;
|
||||||
|
ImageTexture *m_texture;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
131
game/sound/dummy_sound.cpp
Normal file
131
game/sound/dummy_sound.cpp
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#include "sound.hpp"
|
||||||
|
|
||||||
|
namespace sound {
|
||||||
|
bool initSound(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteOldSounds()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundHandle *playSound(enum Sound type, float amplitude)
|
||||||
|
{
|
||||||
|
(void) type;
|
||||||
|
(void) amplitude;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundHandle *playFrequency(float freq, float amplitude)
|
||||||
|
{
|
||||||
|
(void) freq;
|
||||||
|
(void) amplitude;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configureEnvelope(SoundHandle *handle, float rise, float hold, float decay)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) rise;
|
||||||
|
(void) hold;
|
||||||
|
(void) decay;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configureOvershoot(SoundHandle *handle, float relativeOvershootTime)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) relativeOvershootTime;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configureEnvelopeWait(SoundHandle *handle, float rise, float hold, float decay, float wait)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) rise;
|
||||||
|
(void) hold;
|
||||||
|
(void) decay;
|
||||||
|
(void) wait;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configureEnvelopeLooping(SoundHandle *handle, float rise, float hold, float decay, float wait)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) rise;
|
||||||
|
(void) hold;
|
||||||
|
(void) decay;
|
||||||
|
(void) wait;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getRiseDuration(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
float getHoldDuration(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getDecayDuration(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getWaitTime(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void configureWaitTime(SoundHandle *handle, float waitTime)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) waitTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLoopCount(SoundHandle *handle, int numRepetitions)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
(void) numRepetitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stopSound(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopAllSounds(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void teardownSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool startDumpingWav(const char *filename)
|
||||||
|
{
|
||||||
|
(void) filename;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopDumpingWav(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int numActiveSounds(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteSound(SoundHandle *handle)
|
||||||
|
{
|
||||||
|
(void) handle;
|
||||||
|
}
|
||||||
|
}
|
1071
game/sound/sound.cpp
Normal file
1071
game/sound/sound.cpp
Normal file
File diff suppressed because it is too large
Load diff
196
game/sound/sound.hpp
Normal file
196
game/sound/sound.hpp
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
#ifndef _SOUND_HPP_
|
||||||
|
#define _SOUND_HPP_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
namespace sound {
|
||||||
|
|
||||||
|
// type of sound.
|
||||||
|
// the envelope settings modify each sound.
|
||||||
|
enum Sound {
|
||||||
|
SoundFrequency=0, // one frequency
|
||||||
|
SoundWhiteNoise=1, // all frequencies are equal
|
||||||
|
SoundBrownianNoise=2, // 1/f^2 noise
|
||||||
|
SoundPinkNoise=3, // 1/f noise
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EnvelopeState {
|
||||||
|
New=0, // newly spawned
|
||||||
|
Wait, // ready but not yet started (waiting before starting or before repeating)
|
||||||
|
Rise, // increasing
|
||||||
|
BeginOvershoot,
|
||||||
|
EndOvershoot,
|
||||||
|
Hold, // staying at normal level
|
||||||
|
Decay, // deacying
|
||||||
|
Done, // done
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SoundDecayType {
|
||||||
|
SoundDecayLinear = 0,
|
||||||
|
SoundDecayExp = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundHandle {
|
||||||
|
// just for debugging/logging. don't rely on use
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
// unique ID for accessing them via lookups etc. if sound is dead, this will be never reused
|
||||||
|
size_t uid;
|
||||||
|
|
||||||
|
// marked for deletion by the internal thread.
|
||||||
|
bool deleteFlag;
|
||||||
|
|
||||||
|
// is now deleted. when a new sound should be used, this can be reused
|
||||||
|
// and at the end deleteFlag and isDeleted should be cleared.
|
||||||
|
bool isDeleted;
|
||||||
|
|
||||||
|
// if true, don't deallocate once this is done.
|
||||||
|
bool keep_when_done;
|
||||||
|
|
||||||
|
// these are public and can be changed by the user.
|
||||||
|
enum EnvelopeState envelope;
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* Special Parameters for specific types */
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
/******************** SoundFrequency ****************************/
|
||||||
|
|
||||||
|
float freq; // base frequency for type: SoundFrequency
|
||||||
|
|
||||||
|
/******************** White / Brownian / Pink Noise ****************/
|
||||||
|
float leakage; // influence of previous state on current value (0..1)
|
||||||
|
float scaling; // influence of white noise on next value
|
||||||
|
|
||||||
|
// If true and the value goes outside (-1..1), do the step in the other
|
||||||
|
// direction to stay inside the valid range.
|
||||||
|
bool skipDirectionIfClamping;
|
||||||
|
|
||||||
|
/******************** SoundFrequency: ***************************/
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* Common sound state / parameters */
|
||||||
|
/****************************************************************/
|
||||||
|
// progress of the sound which is used for the envelope but can be used for
|
||||||
|
// other things too
|
||||||
|
float time;
|
||||||
|
|
||||||
|
// scalar state that can be used arbitrarily to derive the waveform from it
|
||||||
|
float state;
|
||||||
|
|
||||||
|
// time when the sound is done
|
||||||
|
// if != 0.0, the sound changes with that
|
||||||
|
// TODO: make attack gain decay stuff as envelope
|
||||||
|
// TODO: add amplitude noise
|
||||||
|
float _riseTime;
|
||||||
|
float _relativeOvershootTime; // percentage of end of rise time that is used for overshoot (max amplitude at t_overshoot/2)
|
||||||
|
float _holdTime;
|
||||||
|
float _decayTime;
|
||||||
|
float _waitTime;
|
||||||
|
|
||||||
|
// waveform of type of rise. default: linear
|
||||||
|
enum SoundDecayType riseType;
|
||||||
|
|
||||||
|
// waveform of type of decay. default: linear
|
||||||
|
enum SoundDecayType decayType;
|
||||||
|
|
||||||
|
// if true, play infinitely
|
||||||
|
bool looping;
|
||||||
|
|
||||||
|
// base amplitude of the sound
|
||||||
|
float amplitude;
|
||||||
|
|
||||||
|
// amplitude when signal is at minimum (before rise, after release and in wait time)
|
||||||
|
float minAmplitude;
|
||||||
|
|
||||||
|
// these are al private!
|
||||||
|
// never acces them
|
||||||
|
enum Sound _type; // which type of sound
|
||||||
|
|
||||||
|
int _loopCount;
|
||||||
|
|
||||||
|
// if true, will get removed
|
||||||
|
bool _done;
|
||||||
|
bool _useEnvelope;
|
||||||
|
|
||||||
|
float *history; // if != 0, history is a pointer to 2*numHistorySamples samples.
|
||||||
|
size_t numHistorySamples; // if != 0, save history for this sound.
|
||||||
|
size_t lastHistorySample; // index/2 of last history sample. used
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialize sound subsystem. return true if working, false on errors.
|
||||||
|
bool initSound(void);
|
||||||
|
|
||||||
|
// free sounds that are not used anymore.
|
||||||
|
// must be called regularily by the application
|
||||||
|
void deleteOldSounds();
|
||||||
|
|
||||||
|
// start playing a sound.
|
||||||
|
// args:
|
||||||
|
// type - type of sound.
|
||||||
|
// amplitude : 0..1
|
||||||
|
// handle: if != NULL will point to the internal sound handle to change the
|
||||||
|
// manipulate playing of the sound.
|
||||||
|
// TODO: add sound from file to play too
|
||||||
|
SoundHandle *playSound(enum Sound type, float amplitude);
|
||||||
|
|
||||||
|
// start playing a looping frequency.
|
||||||
|
// args:
|
||||||
|
// freq: frequency in Hz
|
||||||
|
SoundHandle *playFrequency(float freq, float amplitude);
|
||||||
|
|
||||||
|
// set them.
|
||||||
|
// args:
|
||||||
|
// time of phases
|
||||||
|
bool configureEnvelope(SoundHandle *handle, float rise, float hold, float decay);
|
||||||
|
|
||||||
|
bool configureOvershoot(SoundHandle *handle, float relativeOvershootTime);
|
||||||
|
|
||||||
|
// same as above but set to looping and set wait time between intervals
|
||||||
|
bool configureEnvelopeWait(SoundHandle *handle, float rise, float hold, float decay, float wait);
|
||||||
|
|
||||||
|
// without looping but with wait
|
||||||
|
bool configureEnvelopeLooping(SoundHandle *handle, float rise, float hold, float decay, float wait);
|
||||||
|
|
||||||
|
// getter for attributes. if 0.0, unused.
|
||||||
|
float getRiseDuration(SoundHandle *handle);
|
||||||
|
float getHoldDuration(SoundHandle *handle);
|
||||||
|
float getDecayDuration(SoundHandle *handle);
|
||||||
|
|
||||||
|
float getWaitTime(SoundHandle *handle);
|
||||||
|
void configureWaitTime(SoundHandle *handle, float waitTime);
|
||||||
|
|
||||||
|
// Set looping behaviour of the sound.
|
||||||
|
// args:
|
||||||
|
// / > 0, sound is looping for this number of repetitions
|
||||||
|
// numRepetitions { == 0, sound is stopped when it is over
|
||||||
|
// \ == -1, loop the sound forever
|
||||||
|
//
|
||||||
|
void setLoopCount(SoundHandle *handle, int numRepetitions);
|
||||||
|
|
||||||
|
// stop playing a sound. the handle is invalid now.
|
||||||
|
bool stopSound(SoundHandle *handle);
|
||||||
|
|
||||||
|
// stop and remove all playing sounds. all handle become invalid after calling
|
||||||
|
// this.
|
||||||
|
void stopAllSounds(void);
|
||||||
|
|
||||||
|
void teardownSound(void);
|
||||||
|
|
||||||
|
// for debugging
|
||||||
|
bool startDumpingWav(const char *filename);
|
||||||
|
|
||||||
|
// is deletede when 'keep' not set after stopping
|
||||||
|
void stopDumpingWav(void);
|
||||||
|
|
||||||
|
int numActiveSounds(void);
|
||||||
|
|
||||||
|
void deleteSound(SoundHandle *handle);
|
||||||
|
|
||||||
|
//SoundHandle *playFreqEnvelope(float freq, float rise, float hold, float decay);
|
||||||
|
|
||||||
|
// TODO: add fade out/fade in overlay stuff for stopping sounds smoothly
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
83
game/sound/sound_effects.cpp
Normal file
83
game/sound/sound_effects.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include "sound_effects.hpp"
|
||||||
|
|
||||||
|
#include "sound.hpp"
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
namespace sound {
|
||||||
|
void SoundEffects::addSoundHandleForObject(game::Object *obj, SoundHandle *handle)
|
||||||
|
{
|
||||||
|
std::cout<<"add sound for object: " << obj->id << std::endl;
|
||||||
|
auto pair = std::pair<size_t, SoundHandle*>(obj->id, handle);
|
||||||
|
m_mapObjectToSoundHandle.insert(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SoundEffects::fadeOutSoundHandlesForObject(game::Object *obj, float fadeOutTime)
|
||||||
|
{
|
||||||
|
std::cout<<"deleting sounds for object: " << obj->id << std::endl;
|
||||||
|
std::multimap<size_t, SoundHandle*>::iterator it;
|
||||||
|
for (it = m_mapObjectToSoundHandle.find(obj->id); it != m_mapObjectToSoundHandle.end(); it++) {
|
||||||
|
std::cout<<"sound #" << it->second->uid << " / " << it->second->name << std::endl;
|
||||||
|
fadeOut(it->second, fadeOutTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numRemoved = m_mapObjectToSoundHandle.erase(obj->id);
|
||||||
|
std::cout<<"removed total sounds: " << numRemoved << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffects::advance(float dt, const std::list<game::StateUpdateEvent*> &updates)
|
||||||
|
{
|
||||||
|
(void) dt;
|
||||||
|
|
||||||
|
for (const game::StateUpdateEvent *evt : updates) {
|
||||||
|
auto type = evt->eventType();
|
||||||
|
auto cycle = evt->lifeCycle();
|
||||||
|
if (type == game::EventType::Missile) {
|
||||||
|
if (cycle == game::LifeCycle::Create) {
|
||||||
|
SoundHandle *handle = playFrequency(880.0, 0.1);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fadeIn(handle);
|
||||||
|
handle->name = "missile-fly-sound_fade-in";
|
||||||
|
|
||||||
|
addSoundHandleForObject(evt->object(), handle);
|
||||||
|
|
||||||
|
} else if (cycle == game::LifeCycle::Destroy) {
|
||||||
|
fadeOutSoundHandlesForObject(evt->object());
|
||||||
|
}
|
||||||
|
} else if (type == game::EventType::Explosion) {
|
||||||
|
#if 1
|
||||||
|
if (cycle == game::LifeCycle::Create) {
|
||||||
|
SoundHandle *handle = playSound(SoundBrownianNoise, 0.4);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
configureEnvelope(handle, 0.2, 0.0, 2.0);
|
||||||
|
|
||||||
|
// add big *boom* sound too
|
||||||
|
handle = playFrequency(200.0, 0.5);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
configureEnvelope(handle, 0.1, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffects::fadeIn(SoundHandle *handle, float fadeInTime)
|
||||||
|
{
|
||||||
|
// assume sound has just started
|
||||||
|
configureEnvelope(handle, fadeInTime, 1000000.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffects::fadeOut(SoundHandle *handle, float fadeOutTime)
|
||||||
|
{
|
||||||
|
// reset time so it imediately starts to fade out.
|
||||||
|
configureEnvelope(handle, 0.0, 0.0, fadeOutTime);
|
||||||
|
handle->time = 0.0;
|
||||||
|
}
|
||||||
|
}
|
43
game/sound/sound_effects.hpp
Normal file
43
game/sound/sound_effects.hpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "state/state.hpp"
|
||||||
|
|
||||||
|
namespace sound {
|
||||||
|
struct SoundHandle;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
class SoundEffect {
|
||||||
|
public:
|
||||||
|
virtual ~SoundEffects()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// return false if it can be deleted
|
||||||
|
virtual bool advance(float dt) = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SoundEffects {
|
||||||
|
public:
|
||||||
|
SoundEffects()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance(float dt, const std::list<game::StateUpdateEvent*> &updates);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fadeIn(SoundHandle *handle, float fadeInTime=0.3f);
|
||||||
|
void fadeOut(SoundHandle *handle, float fadeOutTime=0.3f);
|
||||||
|
|
||||||
|
void addSoundHandleForObject(game::Object *obj, SoundHandle *handle);
|
||||||
|
void fadeOutSoundHandlesForObject(game::Object *obj, float fadeOutTime=0.3f);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<SoundHandle*> m_soundHandles;
|
||||||
|
std::multimap<size_t, SoundHandle*> m_mapObjectToSoundHandle;
|
||||||
|
//std::list<SoundEffect*> m_effects;
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
#include "trace.hpp"
|
#include "trace.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include "developer_console.hpp"
|
||||||
|
|
||||||
namespace game {
|
namespace game {
|
||||||
void ShootCommand::apply(Player *player, State *state) const
|
void ShootCommand::apply(Player *player, State *state) const
|
||||||
{
|
{
|
||||||
|
@ -14,25 +16,24 @@ namespace game {
|
||||||
|
|
||||||
// angles are supplied in degrees and are CCW
|
// angles are supplied in degrees and are CCW
|
||||||
Missile *missile = new Missile(
|
Missile *missile = new Missile(
|
||||||
|
state->generateId(),
|
||||||
player,
|
player,
|
||||||
player->ship->position,
|
player->ship->position,
|
||||||
-util::deg2rad(m_angle),
|
-util::deg2rad(m_angle),
|
||||||
0.005*player->speed);
|
0.005*player->speed);
|
||||||
|
|
||||||
Trace *trace = new Trace(missile);
|
|
||||||
missile->trace = trace;
|
|
||||||
|
|
||||||
player->energy -= player->speed;
|
player->energy -= player->speed;
|
||||||
player->missiles.push_back(missile);
|
player->missiles.push_back(missile);
|
||||||
|
|
||||||
state->addTrace(trace);
|
state->addMissile(missile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShootCommand::ready(const Player *player, const State *state) const
|
bool ShootCommand::ready(const Player *player, const State *state) const
|
||||||
{
|
{
|
||||||
(void) state;
|
(void) state;
|
||||||
|
|
||||||
return player->alive && player->energy >= player->speed;
|
//return player->alive && player->energy >= player->speed;
|
||||||
|
return player->alive;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeNameCommand::apply(Player *player, State *state) const
|
void ChangeNameCommand::apply(Player *player, State *state) const
|
||||||
|
@ -78,6 +79,8 @@ namespace game {
|
||||||
|
|
||||||
void DeveloperCommand::apply(Player *player, State *state) const
|
void DeveloperCommand::apply(Player *player, State *state) const
|
||||||
{
|
{
|
||||||
|
(void) player;
|
||||||
|
|
||||||
if (!state->developerMode()) {
|
if (!state->developerMode()) {
|
||||||
std::cout<<"ignoring dev command while not in developer mode: '"
|
std::cout<<"ignoring dev command while not in developer mode: '"
|
||||||
<< m_payload << "'" << std::endl;
|
<< m_payload << "'" << std::endl;
|
||||||
|
@ -90,14 +93,26 @@ namespace game {
|
||||||
|
|
||||||
std::cout << "got developer command: '" << m_payload << "'" << std::endl;
|
std::cout << "got developer command: '" << m_payload << "'" << std::endl;
|
||||||
|
|
||||||
if (m_payload == "reload shader") {
|
std::string nextToken;
|
||||||
// TODO: really do that ;)
|
std::string nextPayload;
|
||||||
} else if (m_payload == "reload models") {
|
|
||||||
|
if (util::splitIntoTokenAndRest(m_payload, nextToken, nextPayload)) {
|
||||||
|
developer::DeveloperConsole::CallbackResult result =
|
||||||
|
developer::DeveloperConsole::instance().dispatchInput(
|
||||||
|
nextToken,
|
||||||
|
nextPayload);
|
||||||
|
|
||||||
|
if (result.okay) {
|
||||||
|
std::cout<<"[commands] developer callback success: " << result.answer << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout<<"[commands] developer callback failure: " << result.answer << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDeveloperModeCommand::apply(Player *player, State *state) const
|
void SetDeveloperModeCommand::apply(Player *player, State *state) const
|
||||||
{
|
{
|
||||||
|
(void) player;
|
||||||
// TODO: check if player is admin
|
// TODO: check if player is admin
|
||||||
|
|
||||||
state->setDeveloperMode(m_enable);
|
state->setDeveloperMode(m_enable);
|
||||||
|
|
14
game/state/events/explosion_event.hpp
Normal file
14
game/state/events/explosion_event.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "state/explosion.hpp"
|
||||||
|
#include "state/state_update_event.hpp"
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
class ExplosionEvent : public StateUpdateEvent {
|
||||||
|
public:
|
||||||
|
ExplosionEvent(LifeCycle lifeCycle, Explosion *explosion)
|
||||||
|
: StateUpdateEvent(lifeCycle, EventType::Explosion, explosion)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
14
game/state/events/missile_event.hpp
Normal file
14
game/state/events/missile_event.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "state/missile.hpp"
|
||||||
|
#include "state/state_update_event.hpp"
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
class MissileEvent : public StateUpdateEvent {
|
||||||
|
public:
|
||||||
|
MissileEvent(LifeCycle lifeCycle, Missile *missile)
|
||||||
|
: StateUpdateEvent(lifeCycle, EventType::Missile, missile)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
14
game/state/events/ship_event.hpp
Normal file
14
game/state/events/ship_event.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "state/ship.hpp"
|
||||||
|
#include "state/state_update_event.hpp"
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
class ShipEvent : public StateUpdateEvent {
|
||||||
|
public:
|
||||||
|
ShipEvent(LifeCycle lifeCycle, Ship *ship)
|
||||||
|
: StateUpdateEvent(lifeCycle, EventType::Ship, ship)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "explosion.hpp"
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
size_t s_id_counter = 0;
|
||||||
|
|
||||||
|
Explosion::Explosion(size_t id, const glm::vec2 &pos, const glm::vec2 &missileVelocity, Hit hit, float maxAge)
|
||||||
|
: Object(id, pos)
|
||||||
|
, hit(hit)
|
||||||
|
, missileVelocity(missileVelocity)
|
||||||
|
, age(0.0)
|
||||||
|
, maxAge(maxAge * (1.0 + 0.1*util::randf_0_1()))
|
||||||
|
, maxRadius(0.05)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <glm/vec2.hpp>
|
#include "object.hpp"
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
|
@ -10,21 +10,12 @@ namespace game {
|
||||||
/**
|
/**
|
||||||
* Explosion: just an effect which looks good.
|
* Explosion: just an effect which looks good.
|
||||||
*/
|
*/
|
||||||
class Explosion {
|
class Explosion : public Object {
|
||||||
public:
|
public:
|
||||||
Explosion(const glm::vec2 &pos, Hit hit, float maxAge=1.0)
|
Explosion(size_t id, const glm::vec2 &pos, const glm::vec2 &missileVelocity, Hit hit, float maxAge=1.0);
|
||||||
: hit(hit)
|
|
||||||
, position(pos)
|
|
||||||
, age(0.0)
|
|
||||||
, maxAge(maxAge * (1.0 + 0.1*util::randf_0_1()))
|
|
||||||
, maxRadius(0.05)
|
|
||||||
{
|
|
||||||
static size_t id_counter = 0;
|
|
||||||
id = id_counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Hit hit; // kind of the explosion depends on the hit type
|
const Hit hit; // kind of the explosion depends on the hit type
|
||||||
const glm::vec2 position; // position where it starts
|
const glm::vec2 missileVelocity; // impact velocity of the missile
|
||||||
float age; // age (in seconsd) of the explosion
|
float age; // age (in seconsd) of the explosion
|
||||||
|
|
||||||
// age (in seconds) when the explosion is not visible
|
// age (in seconds) when the explosion is not visible
|
||||||
|
@ -32,6 +23,6 @@ namespace game {
|
||||||
const float maxAge;
|
const float maxAge;
|
||||||
const float maxRadius; // current radius depends on time.
|
const float maxRadius; // current radius depends on time.
|
||||||
|
|
||||||
size_t id;
|
//virtual void test() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
namespace game {
|
namespace game {
|
||||||
Missile::Missile(Player *player, const glm::vec2 &pos, float angle, float speed)
|
Missile::Missile(size_t id, Player *player, const glm::vec2 &pos, float angle, float speed)
|
||||||
: player(player)
|
: Object(id, pos)
|
||||||
, position(pos)
|
, player(player)
|
||||||
{
|
{
|
||||||
velocity = speed * glm::vec2(std::sin(angle), std::cos(angle));
|
velocity = speed * glm::vec2(std::sin(angle), std::cos(angle));
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace game {
|
||||||
if (dist <= other->ship->radius) {
|
if (dist <= other->ship->radius) {
|
||||||
// TODO: collect all hits and return the first one only
|
// TODO: collect all hits and return the first one only
|
||||||
// TODO: find exact hit position!
|
// TODO: find exact hit position!
|
||||||
return Missile::Event(position, player->id, other->id);
|
return Missile::Event(position, velocity, player->id, other->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ namespace game {
|
||||||
if (dist <= planet->radius) {
|
if (dist <= planet->radius) {
|
||||||
// TODO: collect all hits and return the first one only
|
// TODO: collect all hits and return the first one only
|
||||||
// TODO: find exact hit position!
|
// TODO: find exact hit position!
|
||||||
return Missile::Event(position, planet->id);
|
return Missile::Event(position, velocity, planet->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
dist *= 20.0;
|
dist *= 20.0;
|
||||||
|
@ -77,9 +77,9 @@ namespace game {
|
||||||
// check if distance to center of the universe is getting too big
|
// check if distance to center of the universe is getting too big
|
||||||
float distToCenter = glm::length(position);
|
float distToCenter = glm::length(position);
|
||||||
if (distToCenter > state->maxMissileDistance()) {
|
if (distToCenter > state->maxMissileDistance()) {
|
||||||
return Missile::Event(position, Hit::BorderOfUniverse);
|
return Missile::Event(position, velocity, Hit::BorderOfUniverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Missile::Event(position);
|
return Missile::Event(position, velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "object.hpp"
|
||||||
|
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
#include <glm/vec3.hpp>
|
|
||||||
|
|
||||||
#include "missile_hit_type.hpp"
|
#include "missile_hit_type.hpp"
|
||||||
|
|
||||||
|
@ -15,30 +16,31 @@ namespace game {
|
||||||
|
|
||||||
// missile belongs to a player and optionally fills a trace behind it.
|
// missile belongs to a player and optionally fills a trace behind it.
|
||||||
// trace then belongs to the player.
|
// trace then belongs to the player.
|
||||||
class Missile {
|
class Missile : public Object {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// missile advances to pos. if hit != Nothing, it hits something and
|
// missile advances to pos. if hit != Nothing, it hits something and
|
||||||
// stops existing afterwards.
|
// stops existing afterwards.
|
||||||
class Event {
|
class Event {
|
||||||
public:
|
public:
|
||||||
Event(const glm::vec2 &pos)
|
Event(const glm::vec2 &pos, const glm::vec2 &missileVelocity)
|
||||||
: Event(pos, Hit::Nothing)
|
: Event(pos, missileVelocity, Hit::Nothing)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Event(const glm::vec2 &pos, Hit hit)
|
Event(const glm::vec2 &pos, const glm::vec2 &missileVelocity, Hit hit)
|
||||||
: hit(hit), position(pos)
|
: hit(hit), position(pos), missileVelocity(missileVelocity)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Event(const glm::vec2 &pos, int planetId) : Event(pos, Hit::Planet)
|
Event(const glm::vec2 &pos, const glm::vec2 &missileVelocity, size_t planetId)
|
||||||
|
: Event(pos, missileVelocity, Hit::Planet)
|
||||||
{
|
{
|
||||||
this->planetId = planetId;
|
this->planetId = planetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Event(const glm::vec2 &pos, int playerIdKiller, int playerIdVictim)
|
Event(const glm::vec2 &pos, const glm::vec2 &missileVelocity, size_t playerIdKiller, size_t playerIdVictim)
|
||||||
: Event(pos, Hit::Ship)
|
: Event(pos, missileVelocity, Hit::Ship)
|
||||||
{
|
{
|
||||||
this->playerIdKiller = playerIdKiller;
|
this->playerIdKiller = playerIdKiller;
|
||||||
this->playerIdVictim = playerIdVictim;
|
this->playerIdVictim = playerIdVictim;
|
||||||
|
@ -46,16 +48,17 @@ namespace game {
|
||||||
|
|
||||||
Hit hit;
|
Hit hit;
|
||||||
glm::vec2 position;
|
glm::vec2 position;
|
||||||
|
glm::vec2 missileVelocity;
|
||||||
|
|
||||||
// if a player was hit, these are valid.
|
// if a player was hit, these are valid.
|
||||||
int playerIdKiller;
|
size_t playerIdKiller;
|
||||||
int playerIdVictim;
|
size_t playerIdVictim;
|
||||||
|
|
||||||
// if a planet was hit, this is valid
|
// if a planet was hit, this is valid
|
||||||
int planetId;
|
size_t planetId;
|
||||||
};
|
};
|
||||||
|
|
||||||
Missile(Player *player, const glm::vec2 &pos, float angle, float speed);
|
Missile(size_t id, Player *player, const glm::vec2 &pos, float angle, float speed);
|
||||||
~Missile();
|
~Missile();
|
||||||
|
|
||||||
// try to advance. if something will be hit, return the first hit in
|
// try to advance. if something will be hit, return the first hit in
|
||||||
|
@ -63,7 +66,6 @@ namespace game {
|
||||||
Missile::Event advance(const game::State *state, float dt);
|
Missile::Event advance(const game::State *state, float dt);
|
||||||
|
|
||||||
Player *player; // owner won't be hit by own missiles
|
Player *player; // owner won't be hit by own missiles
|
||||||
glm::vec2 position;
|
|
||||||
glm::vec2 velocity;
|
glm::vec2 velocity;
|
||||||
Trace *trace;
|
Trace *trace;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
|
namespace game {
|
||||||
class Object {
|
class Object {
|
||||||
public:
|
public:
|
||||||
Object(const glm::vec2 &pos, float r) : position(pos), radius(r)
|
Object(size_t id, const glm::vec2 &pos) : id(id), position(pos)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec2 position;
|
const size_t id;
|
||||||
const float radius;
|
glm::vec2 position;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -13,24 +13,18 @@ class Planet : public Object {
|
||||||
*/
|
*/
|
||||||
enum class Material { Rock=0, Metal=1, Sand=2, Gas=3, Ice=4, Water=5, Sun=6 };
|
enum class Material { Rock=0, Metal=1, Sand=2, Gas=3, Ice=4, Water=5, Sun=6 };
|
||||||
|
|
||||||
Planet(const glm::vec2 &pos, int id, float r)
|
Planet(size_t id, const glm::vec2 &pos, float r, Material mat=Material::Rock)
|
||||||
: Planet(pos, id, r, Material::Rock)
|
: Object(id, pos), material(mat), radius(r), seed(rand())
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Planet(const glm::vec2 &pos, int id, float r, Material mat)
|
|
||||||
: Object(pos, r), id(id), material(mat), seed(rand())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 getColor() const;
|
glm::vec3 getColor() const;
|
||||||
|
|
||||||
int id;
|
|
||||||
|
|
||||||
// for rendering and physics (can fly through sun and outer gas planets)
|
// for rendering and physics (can fly through sun and outer gas planets)
|
||||||
Material material;
|
Material material;
|
||||||
|
|
||||||
// just for rendering variation
|
// just for rendering variation
|
||||||
|
float radius;
|
||||||
int seed;
|
int seed;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace game {
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
public:
|
public:
|
||||||
int id;
|
size_t id;
|
||||||
bool alive;
|
bool alive;
|
||||||
float speed;
|
float speed;
|
||||||
float energy;
|
float energy;
|
||||||
|
@ -23,7 +23,7 @@ namespace game {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::list<Missile*> missiles;
|
std::list<Missile*> missiles;
|
||||||
|
|
||||||
Player(int id) : id(id), alive(true), speed(1.0), energy(0.0), ship(nullptr), name("<unnamed>")
|
Player(size_t id) : id(id), alive(true), speed(1.0), energy(0.0), ship(nullptr), name("<unnamed>")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
namespace game {
|
namespace game {
|
||||||
class Ship : public Object {
|
class Ship : public Object {
|
||||||
public:
|
public:
|
||||||
Ship(const glm::vec2 &pos, float r) : Object(pos, r)
|
Ship(size_t id, const glm::vec2 &pos, float r) : Object(id, pos), radius(r)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float radius;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,77 +10,63 @@
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "missile.hpp"
|
#include "missile.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "planet.hpp"
|
|
||||||
#include "ship.hpp"
|
#include "ship.hpp"
|
||||||
#include "commands.hpp"
|
#include "commands.hpp"
|
||||||
#include "trace.hpp"
|
#include "trace.hpp"
|
||||||
#include "explosion.hpp"
|
#include "explosion.hpp"
|
||||||
|
|
||||||
|
#include "events/explosion_event.hpp"
|
||||||
|
#include "events/missile_event.hpp"
|
||||||
|
#include "events/ship_event.hpp"
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
namespace game {
|
namespace game {
|
||||||
void State::init(int numPlanets, bool devMode)
|
void State::init(int numPlanets)
|
||||||
{
|
{
|
||||||
m_nextId = 0;
|
// clear
|
||||||
|
for (Planet *planet : planets) {
|
||||||
|
delete(planet);
|
||||||
|
}
|
||||||
|
planets.clear();
|
||||||
|
|
||||||
|
// TODO: clear shots etc. too
|
||||||
|
|
||||||
m_time = 0.0;
|
m_time = 0.0;
|
||||||
m_shipRadius = 0.02;
|
m_shipRadius = 0.02;
|
||||||
m_maxMissileDistance = 2.0;
|
m_maxMissileDistance = 2.0;
|
||||||
m_playerRespawnTime = 2.0;
|
m_playerRespawnTime = 2.0;
|
||||||
m_defaultEnergy = 10.0;
|
m_defaultEnergy = 10.0;
|
||||||
m_maxNumTraces = 10;
|
m_maxNumTraces = 10;
|
||||||
m_developerMode = devMode;
|
|
||||||
|
|
||||||
Planet::Material mat = Planet::Material::Rock;
|
setPlayingFieldCenter(0, 0);
|
||||||
|
|
||||||
for (int i=0; i<numPlanets; i++) {
|
// TODO: need aspect ratio or data!
|
||||||
switch(i) {
|
//setPlayingFieldSize(1000, 300);
|
||||||
case 0:
|
|
||||||
mat = Planet::Material::Sun;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
setupPlanets(numPlanets);
|
||||||
case 2:
|
|
||||||
mat = Planet::Material::Water;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
mat = Planet::Material::Sand;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
mat = Planet::Material::Metal;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
mat = Planet::Material::Rock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 pos;
|
bool State::findPlanetSpawnPosition(bool planetIsSun, float radius, glm::vec2 *pos)
|
||||||
float radius = 0.03 + 0.07*util::randf_0_1();
|
{
|
||||||
if (i == 0) {
|
(void) planetIsSun;
|
||||||
// sun is bigger but not too big
|
|
||||||
radius += 0.05;
|
|
||||||
if (radius > 0.9) {
|
|
||||||
radius = 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tooNearToCenter = true;
|
bool tooNearToCenter = true;
|
||||||
bool collidesWithOtherPlanet = true;
|
bool collidesWithOtherPlanet = true;
|
||||||
|
|
||||||
|
const glm::vec2 spawnArea = 0.9f * (m_playingFieldSize/std::max(m_playingFieldSize.x, m_playingFieldSize.y));
|
||||||
|
|
||||||
// distribute but not in the center and not next to other planets
|
// distribute but not in the center and not next to other planets
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
do {
|
do {
|
||||||
pos = util::randv2_m1_1();
|
*pos = spawnArea * util::randv2_m1_1();
|
||||||
|
|
||||||
collidesWithOtherPlanet = false;
|
collidesWithOtherPlanet = false;
|
||||||
tooNearToCenter = glm::length(pos) < 0.1;
|
tooNearToCenter = glm::length(*pos) < 0.1;
|
||||||
|
|
||||||
if (!tooNearToCenter) {
|
if (!tooNearToCenter) {
|
||||||
for (const Planet *other : planets) {
|
for (const Planet *other : planets) {
|
||||||
float d = glm::distance(other->position, pos);
|
float d = glm::distance(other->position, *pos);
|
||||||
|
|
||||||
float extraDist = (other->material == Planet::Material::Sun)
|
float extraDist = (other->material == Planet::Material::Sun)
|
||||||
? 4.0
|
? 4.0
|
||||||
|
@ -92,10 +78,57 @@ namespace game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (tries++ > 1000) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} while((collidesWithOtherPlanet || tooNearToCenter) && tries++ < 1000);
|
} while(collidesWithOtherPlanet || tooNearToCenter);
|
||||||
|
|
||||||
planets.push_back(new Planet(pos, i, radius, mat));
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::setupPlanets(int numPlanets)
|
||||||
|
{
|
||||||
|
for (int i=0; i<numPlanets; i++) {
|
||||||
|
Planet::Material mat = materialForStandardPlanetDistribution(i);
|
||||||
|
|
||||||
|
float radius = 0.03 + 0.07*util::randf_0_1();
|
||||||
|
if (i == 0) {
|
||||||
|
// sun is bigger but not too big
|
||||||
|
radius += 0.05;
|
||||||
|
if (radius > 0.9) {
|
||||||
|
radius = 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 pos;
|
||||||
|
if (findPlanetSpawnPosition(mat == Planet::Material::Sun, radius, &pos)) {
|
||||||
|
planets.push_back(new Planet(i, pos, radius, mat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Planet::Material State::materialForStandardPlanetDistribution(int index)
|
||||||
|
{
|
||||||
|
// a few sun/water/sand/metall planents and the rest rocks
|
||||||
|
switch(index) {
|
||||||
|
case 0:
|
||||||
|
return Planet::Material::Sun;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return Planet::Material::Water;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
return Planet::Material::Sand;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return Planet::Material::Metal;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Planet::Material::Rock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,23 +139,25 @@ namespace game {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
player->ship = new Ship(spawnPos, m_shipRadius);
|
Ship *ship = new Ship(generateId(), spawnPos, m_shipRadius);
|
||||||
ships.push_back(player->ship);
|
player->ship = ship;
|
||||||
|
ships.push_back(ship);
|
||||||
|
|
||||||
player->energy = m_defaultEnergy;
|
player->energy = m_defaultEnergy;
|
||||||
|
|
||||||
|
addShip(ship);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int State::addPlayer()
|
size_t State::addPlayer()
|
||||||
{
|
{
|
||||||
int playerId = m_nextId++;
|
Player *player = new Player(generateId());
|
||||||
Player *player = new Player(playerId);
|
|
||||||
players.push_back(player);
|
players.push_back(player);
|
||||||
return playerId;
|
return player->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::quitPlayer(int playerId)
|
void State::quitPlayer(size_t playerId)
|
||||||
{
|
{
|
||||||
std::cout << playerId << " quit" << std::endl;
|
std::cout << playerId << " quit" << std::endl;
|
||||||
|
|
||||||
|
@ -136,12 +171,12 @@ namespace game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::clear(int playerId)
|
void State::clear(size_t playerId)
|
||||||
{
|
{
|
||||||
std::cout << playerId << " clear" << std::endl;
|
std::cout << playerId << " clear" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::setName(int playerId, std::string name)
|
void State::setName(size_t playerId, std::string name)
|
||||||
{
|
{
|
||||||
// discard if not unique
|
// discard if not unique
|
||||||
for (const Player *other : players) {
|
for (const Player *other : players) {
|
||||||
|
@ -154,7 +189,12 @@ namespace game {
|
||||||
playerForId(playerId)->name = name;
|
playerForId(playerId)->name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::setSpeed(int playerId, double speed)
|
void State::addShip(Ship *ship)
|
||||||
|
{
|
||||||
|
m_nextEvents.push_back(new ShipEvent(LifeCycle::Create, ship));
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::setSpeed(size_t playerId, double speed)
|
||||||
{
|
{
|
||||||
playerForId(playerId)->speed = speed;
|
playerForId(playerId)->speed = speed;
|
||||||
}
|
}
|
||||||
|
@ -235,10 +275,7 @@ namespace game {
|
||||||
|
|
||||||
std::vector<Missile*> rm;
|
std::vector<Missile*> rm;
|
||||||
for (Missile *missile : player->missiles) {
|
for (Missile *missile : player->missiles) {
|
||||||
|
|
||||||
//std::cout<<"missile: " << (long unsigned int) missile << std::endl;
|
|
||||||
const Missile::Event evt = missile->advance(this, dt);
|
const Missile::Event evt = missile->advance(this, dt);
|
||||||
|
|
||||||
const bool isHit = (evt.hit != Hit::Nothing);
|
const bool isHit = (evt.hit != Hit::Nothing);
|
||||||
|
|
||||||
if (missile->trace != nullptr) {
|
if (missile->trace != nullptr) {
|
||||||
|
@ -288,7 +325,8 @@ namespace game {
|
||||||
|
|
||||||
for (Missile *missile : rm) {
|
for (Missile *missile : rm) {
|
||||||
player->missiles.remove(missile);
|
player->missiles.remove(missile);
|
||||||
delete(missile);
|
|
||||||
|
m_nextEvents.push_back(new MissileEvent(LifeCycle::Destroy, missile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,12 +344,17 @@ namespace game {
|
||||||
|
|
||||||
for (Explosion *explosion : rm) {
|
for (Explosion *explosion : rm) {
|
||||||
explosions.remove(explosion);
|
explosions.remove(explosion);
|
||||||
delete(explosion);
|
|
||||||
|
m_nextEvents.push_back(new ExplosionEvent(LifeCycle::Destroy, explosion));
|
||||||
|
|
||||||
|
//delete(explosion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::advance(float dt)
|
void State::advance(float dt)
|
||||||
{
|
{
|
||||||
|
//std::cout<<"[state] (init) cycle: update events length is " << m_nextEvents.size() << std::endl;
|
||||||
|
|
||||||
m_time += dt;
|
m_time += dt;
|
||||||
|
|
||||||
advancePlayerShipSpawns(dt);
|
advancePlayerShipSpawns(dt);
|
||||||
|
@ -323,9 +366,23 @@ namespace game {
|
||||||
advancePlayerCommands(dt);
|
advancePlayerCommands(dt);
|
||||||
|
|
||||||
advancePlayerMissiles(dt);
|
advancePlayerMissiles(dt);
|
||||||
|
|
||||||
|
//std::cout<<"[state] (before move) cycle: update events length is " << m_nextEvents.size() << std::endl;
|
||||||
|
|
||||||
|
// put collected events into that list.
|
||||||
|
//m_allEvents.push_back(std::move(m_nextEvents));
|
||||||
|
for (auto *evt : m_nextEvents) {
|
||||||
|
m_allEvents.push_back(evt);
|
||||||
|
}
|
||||||
|
m_nextEvents.clear();
|
||||||
|
|
||||||
|
//std::cout<<"[state] (after move) cycle: update events length is " << m_nextEvents.size() << std::endl;
|
||||||
|
|
||||||
|
// finally remove things.
|
||||||
|
//m_nextEvents.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Player *State::playerForId(int playerId)
|
Player *State::playerForId(size_t playerId)
|
||||||
{
|
{
|
||||||
for (Player *p : players) {
|
for (Player *p : players) {
|
||||||
if (p->id == playerId) {
|
if (p->id == playerId) {
|
||||||
|
@ -370,7 +427,7 @@ namespace game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::commandForPlayer(int playerId, game::Command *cmd)
|
void State::commandForPlayer(size_t playerId, game::Command *cmd)
|
||||||
{
|
{
|
||||||
Player *player = playerForId(playerId);
|
Player *player = playerForId(playerId);
|
||||||
if (player != nullptr) {
|
if (player != nullptr) {
|
||||||
|
@ -393,6 +450,16 @@ namespace game {
|
||||||
traces.push_back(trace);
|
traces.push_back(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void State::addMissile(Missile *missile)
|
||||||
|
{
|
||||||
|
Trace *trace = new Trace(missile);
|
||||||
|
missile->trace = trace;
|
||||||
|
|
||||||
|
addTrace(trace);
|
||||||
|
|
||||||
|
m_nextEvents.push_back(new MissileEvent(LifeCycle::Create, missile));
|
||||||
|
}
|
||||||
|
|
||||||
void State::deleteTrace(Trace *trace)
|
void State::deleteTrace(Trace *trace)
|
||||||
{
|
{
|
||||||
if (trace->missile != nullptr) {
|
if (trace->missile != nullptr) {
|
||||||
|
@ -410,7 +477,13 @@ namespace game {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
explosions.push_back(new Explosion(evt->position, evt->hit));
|
Explosion *explosion = new Explosion(
|
||||||
|
generateId(), evt->position,
|
||||||
|
evt->missileVelocity, evt->hit);
|
||||||
|
|
||||||
|
explosions.push_back(explosion);
|
||||||
|
|
||||||
|
m_nextEvents.push_back(new ExplosionEvent(LifeCycle::Create, explosion));
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::advanceTraceAges(float dt)
|
void State::advanceTraceAges(float dt)
|
||||||
|
@ -430,4 +503,60 @@ namespace game {
|
||||||
deleteTrace(trace);
|
deleteTrace(trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void State::setPlayingFieldCenter(int center_x, int center_y)
|
||||||
|
{
|
||||||
|
m_playingFieldCenter = glm::vec2((float) center_x, (float) center_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::setPlayingFieldSize(int width, int height)
|
||||||
|
{
|
||||||
|
m_playingFieldSize = glm::vec2(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t State::generateId()
|
||||||
|
{
|
||||||
|
return m_ids.makeNextId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::applyAndClearAllOldStateUpdates()
|
||||||
|
{
|
||||||
|
for (auto *evt : m_allEvents) {
|
||||||
|
if (evt->lifeCycle() == LifeCycle::Destroy) {
|
||||||
|
switch(evt->eventType()) {
|
||||||
|
case EventType::Explosion:
|
||||||
|
{
|
||||||
|
ExplosionEvent *ee = static_cast<ExplosionEvent*>(evt);
|
||||||
|
//std::cout<<"got explosion delete event, finally deleting explosion #"
|
||||||
|
// << ee->object()->id << std::endl;
|
||||||
|
|
||||||
|
delete(ee->object());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EventType::Missile:
|
||||||
|
{
|
||||||
|
auto *me = static_cast<MissileEvent*>(evt);
|
||||||
|
//std::cout<<"got missile delete event, finally deleting missile #"
|
||||||
|
// << me->object()->id << std::endl;
|
||||||
|
|
||||||
|
delete(me->object());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::cout<<"warning: unhandled deletion event for: event type "
|
||||||
|
<< (int) evt->eventType() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_allEvents.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<StateUpdateEvent*> &State::currentStateUpdateEvents() const
|
||||||
|
{
|
||||||
|
return m_allEvents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
#include "missile.hpp"
|
#include "missile.hpp"
|
||||||
|
#include "planet.hpp"
|
||||||
|
|
||||||
|
#include "state_update_event.hpp"
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// give points for equipment / better weapons / more energy when:
|
// give points for equipment / better weapons / more energy when:
|
||||||
|
@ -27,11 +30,30 @@ namespace game {
|
||||||
// forward declarations
|
// forward declarations
|
||||||
class Command;
|
class Command;
|
||||||
class Player;
|
class Player;
|
||||||
class Planet;
|
|
||||||
class Ship;
|
class Ship;
|
||||||
class Trace;
|
class Trace;
|
||||||
class Explosion;
|
class Explosion;
|
||||||
|
|
||||||
|
class IdGenerator {
|
||||||
|
public:
|
||||||
|
IdGenerator() : m_nextId(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t makeNextId()
|
||||||
|
{
|
||||||
|
return m_nextId++;
|
||||||
|
if (m_nextId == 0) {
|
||||||
|
std::cerr << "note: id counter just wrapped to 0, "
|
||||||
|
"funny things can happen now." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_nextId;
|
||||||
|
};
|
||||||
|
|
||||||
class State {
|
class State {
|
||||||
public:
|
public:
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
@ -40,7 +62,7 @@ namespace game {
|
||||||
|
|
||||||
// called to setup the state (randomize planets, kill
|
// called to setup the state (randomize planets, kill
|
||||||
// traces/missiles/ships etc.)
|
// traces/missiles/ships etc.)
|
||||||
void init(int numPlanets=15, bool devMode=false);
|
void init(int numPlanets=15);
|
||||||
|
|
||||||
// main method to advance the simulation by the given timestamp in
|
// main method to advance the simulation by the given timestamp in
|
||||||
// seconds.
|
// seconds.
|
||||||
|
@ -52,15 +74,15 @@ namespace game {
|
||||||
|
|
||||||
// The upper layer (network/renderer) calling these three functions
|
// The upper layer (network/renderer) calling these three functions
|
||||||
// should keep id's unique and give one (network) input an id.
|
// should keep id's unique and give one (network) input an id.
|
||||||
int addPlayer();
|
size_t addPlayer();
|
||||||
void clear(int playerId);
|
void clear(size_t playerId);
|
||||||
void setName(int playerId, std::string name);
|
void setName(size_t playerId, std::string name);
|
||||||
void setSpeed(int playerId, double speed);
|
void setSpeed(size_t playerId, double speed);
|
||||||
void quitPlayer(int playerId);
|
void quitPlayer(size_t playerId);
|
||||||
void commandForPlayer(int playerId, Command *cmd);
|
void commandForPlayer(size_t playerId, Command *cmd);
|
||||||
|
|
||||||
// lookup. return nullptr on invalid playerId
|
// lookup. return nullptr on invalid playerId
|
||||||
Player *playerForId(int playerId);
|
Player *playerForId(size_t playerId);
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* Mixed stuff */
|
/* Mixed stuff */
|
||||||
|
@ -71,9 +93,15 @@ namespace game {
|
||||||
// each ship has the same radius
|
// each ship has the same radius
|
||||||
float shipRadius() const { return m_shipRadius; }
|
float shipRadius() const { return m_shipRadius; }
|
||||||
|
|
||||||
// add a trace to the list of traces.
|
// add a trace to the state
|
||||||
void addTrace(Trace *trace);
|
void addTrace(Trace *trace);
|
||||||
|
|
||||||
|
// add a missile to the state
|
||||||
|
void addMissile(Missile *missile);
|
||||||
|
|
||||||
|
// add a ship to the state
|
||||||
|
void addShip(Ship *ship);
|
||||||
|
|
||||||
// delete traces with this command
|
// delete traces with this command
|
||||||
void deleteTrace(Trace *trace); // using a pointer
|
void deleteTrace(Trace *trace); // using a pointer
|
||||||
|
|
||||||
|
@ -91,10 +119,26 @@ namespace game {
|
||||||
m_developerMode = on;
|
m_developerMode = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called when the rendering window changes
|
||||||
|
// TODO: give dpi as information too
|
||||||
|
void setPlayingFieldSize(int width, int height);
|
||||||
|
void setPlayingFieldCenter(int width, int height);
|
||||||
|
|
||||||
|
size_t generateId();
|
||||||
|
|
||||||
|
void applyAndClearAllOldStateUpdates();
|
||||||
|
|
||||||
|
// delete the items for events that are to be removed in proper way
|
||||||
|
// after the events were given to other parts of the application.
|
||||||
|
const std::list<StateUpdateEvent*> ¤tStateUpdateEvents() const;
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* Rendering */
|
/* Rendering */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
|
// TODO: hide and replace by events
|
||||||
|
|
||||||
// Game items which should be rendered are here:
|
// Game items which should be rendered are here:
|
||||||
// (access missiles by iterating over player's missiles attribute)
|
// (access missiles by iterating over player's missiles attribute)
|
||||||
std::vector<Planet*> planets;
|
std::vector<Planet*> planets;
|
||||||
|
@ -111,12 +155,15 @@ namespace game {
|
||||||
void playerKillsPlayer(Player *killer, Player *victim);
|
void playerKillsPlayer(Player *killer, Player *victim);
|
||||||
|
|
||||||
void addExplosionFromHit(const Missile::Event *evt);
|
void addExplosionFromHit(const Missile::Event *evt);
|
||||||
|
bool findPlanetSpawnPosition(bool planetIsSun, float radius, glm::vec2 *pos);
|
||||||
|
|
||||||
void advanceTraceAges(float dt);
|
void advanceTraceAges(float dt);
|
||||||
void advanceExplosions(float dt);
|
void advanceExplosions(float dt);
|
||||||
void advancePlayerShipSpawns(float dt);
|
void advancePlayerShipSpawns(float dt);
|
||||||
void advancePlayerCommands(float dt);
|
void advancePlayerCommands(float dt);
|
||||||
void advancePlayerMissiles(float dt);
|
void advancePlayerMissiles(float dt);
|
||||||
|
void setupPlanets(int numPlanets);
|
||||||
|
Planet::Material materialForStandardPlanetDistribution(int index);
|
||||||
|
|
||||||
// try to spawn a ship for this player.
|
// try to spawn a ship for this player.
|
||||||
// return true on success, false on failure to find a spot.
|
// return true on success, false on failure to find a spot.
|
||||||
|
@ -130,9 +177,15 @@ namespace game {
|
||||||
float m_playerRespawnTime;
|
float m_playerRespawnTime;
|
||||||
float m_shipRadius;
|
float m_shipRadius;
|
||||||
float m_defaultEnergy;
|
float m_defaultEnergy;
|
||||||
int m_nextId;
|
|
||||||
int m_maxNumTraces;
|
int m_maxNumTraces;
|
||||||
|
IdGenerator m_ids;
|
||||||
float m_time;
|
float m_time;
|
||||||
bool m_developerMode;
|
bool m_developerMode;
|
||||||
|
|
||||||
|
glm::vec2 m_playingFieldCenter;
|
||||||
|
glm::vec2 m_playingFieldSize;
|
||||||
|
|
||||||
|
std::list<StateUpdateEvent*> m_nextEvents;
|
||||||
|
std::list<StateUpdateEvent*> m_allEvents;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
73
game/state/state_update_event.hpp
Normal file
73
game/state/state_update_event.hpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "object.hpp"
|
||||||
|
|
||||||
|
// TODO: make life cycle object class.
|
||||||
|
// objects from that class can be created and destroyed only through factory
|
||||||
|
// methods which create updates too.
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
enum class LifeCycle {
|
||||||
|
Create, // something was created
|
||||||
|
Modify, // something was modified (look at attributes)
|
||||||
|
Destroy // something was destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
// add all possible classes here
|
||||||
|
// TODO:
|
||||||
|
// there can be different things in here, like:
|
||||||
|
enum class EventType {
|
||||||
|
Explosion,
|
||||||
|
Missile,
|
||||||
|
Ship
|
||||||
|
};
|
||||||
|
|
||||||
|
class StateUpdateEvent {
|
||||||
|
public:
|
||||||
|
StateUpdateEvent(LifeCycle cycle, EventType event, Object *object, bool changesContinuously=false)
|
||||||
|
: m_lifeCycle(cycle), m_eventType(event)
|
||||||
|
, m_object(object)
|
||||||
|
, m_changesContinuously(changesContinuously)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LifeCycle lifeCycle() const { return m_lifeCycle; }
|
||||||
|
EventType eventType() const { return m_eventType; }
|
||||||
|
bool changesContinuously() const { return m_changesContinuously; }
|
||||||
|
Object* object() const { return m_object; }
|
||||||
|
|
||||||
|
void setChangesContinuously(bool enable) { m_changesContinuously = enable; }
|
||||||
|
|
||||||
|
//std::string description() const
|
||||||
|
//{
|
||||||
|
// // TODO
|
||||||
|
// return "StateUpdateEvent(" + lifeCycleToString(m_lifeCycle) + ", " + eventTypeToString(m_eventType) + ")";
|
||||||
|
//}
|
||||||
|
|
||||||
|
//static std::string lifeCycleToString(LifeCycle lifeCycle)
|
||||||
|
//{
|
||||||
|
// switch(lifeCycle) {
|
||||||
|
// case LifeCycle::Create: return "create";
|
||||||
|
// case LifeCycle::Modify: return "modify";
|
||||||
|
// case LifeCycle::Destroy: return "destroy";
|
||||||
|
// default: return "<no name>";
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//static std::string eventTypeToString(EventType eventType)
|
||||||
|
//{
|
||||||
|
// switch(eventType) {
|
||||||
|
// case EventType::Explosion: return "explosion";
|
||||||
|
// default: return "<no name>";
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const LifeCycle m_lifeCycle;
|
||||||
|
const EventType m_eventType;
|
||||||
|
Object *m_object;
|
||||||
|
bool m_changesContinuously;
|
||||||
|
};
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
float randf_m1_1()
|
float randf_m1_1()
|
||||||
{
|
{
|
||||||
|
@ -33,4 +35,101 @@ namespace util {
|
||||||
{
|
{
|
||||||
return 180.0 * rad / M_PI;
|
return 180.0 * rad / M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntersectionTest::IntersectionTest() : m_valid(false), m_distance(INFINITY)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IntersectionTest::IntersectionTest(float d) : m_valid(true), m_distance(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float IntersectionTest::distance() const { assert(m_valid); return m_distance; }
|
||||||
|
bool IntersectionTest::valid() const { return m_valid; }
|
||||||
|
|
||||||
|
glm::vec3 IntersectionTest::pointAtDistance(float d)
|
||||||
|
{
|
||||||
|
assert(m_valid);
|
||||||
|
return m_rayPos + m_rayDir * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IntersectionTest::raySphere(
|
||||||
|
const glm::vec3 &rayPos, const glm::vec3 &rayDir,
|
||||||
|
const glm::vec3 &spherePos, float sphereRadius)
|
||||||
|
{
|
||||||
|
m_valid = false;
|
||||||
|
|
||||||
|
(void) spherePos;
|
||||||
|
(void) sphereRadius;
|
||||||
|
|
||||||
|
// TODO: save if hit.
|
||||||
|
m_valid = true;
|
||||||
|
m_rayPos = rayPos;
|
||||||
|
m_rayDir = rayDir;
|
||||||
|
m_distance = 0.5;
|
||||||
|
|
||||||
|
// TODO: get code
|
||||||
|
return m_valid;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
const glm::vec3 &o = ray.pos();
|
||||||
|
const glm::vec3 &l = ray.dir();
|
||||||
|
const glm::vec3 &c = m_pos;
|
||||||
|
const float &r = m_radius;
|
||||||
|
|
||||||
|
const glm::vec3 omc = o-c;
|
||||||
|
const float dot = glm::dot(l, omc);
|
||||||
|
const float s = dot*dot - util::dotSelf(omc) + r*r;
|
||||||
|
|
||||||
|
if (s < 0.001) {
|
||||||
|
return RayIntersection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const float t = -dot;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO: is that meant as t?
|
||||||
|
if (s == 0) {
|
||||||
|
// not interested in touch point
|
||||||
|
return RayIntersection();
|
||||||
|
|
||||||
|
//d1 = t;
|
||||||
|
//return RayTouchesOnePoint;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const float sr = sqrt(s);
|
||||||
|
|
||||||
|
d1 = t - sr;
|
||||||
|
d2 = t + sr;
|
||||||
|
|
||||||
|
// if end intersection lies behind it, this is completely uninteresting for us
|
||||||
|
// 0.01 because to get rid of rounding/precision errors
|
||||||
|
if (d2 <= 0.01) {
|
||||||
|
return RayIntersection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the start of the interval lies behind us, make it 0 because we just
|
||||||
|
// want to know whats before us.
|
||||||
|
// 0.01 because to get rid of rounding/precision errors
|
||||||
|
if (d1 < 0.0) {
|
||||||
|
d1 = 0.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool splitIntoTokenAndRest(const std::string &str, std::string &token, std::string &rest)
|
||||||
|
{
|
||||||
|
std::istringstream iss(str);
|
||||||
|
iss >> token;
|
||||||
|
|
||||||
|
if (token.size() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip token + next whitespace
|
||||||
|
rest = str.substr(std::min(str.size(), token.size()+1));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
|
@ -12,4 +15,40 @@ namespace util {
|
||||||
|
|
||||||
float deg2rad(float deg);
|
float deg2rad(float deg);
|
||||||
float rad2deg(float rad);
|
float rad2deg(float rad);
|
||||||
|
|
||||||
|
// split on whitespace into first token and the rest.
|
||||||
|
// return true if whitespace was found or just the token.
|
||||||
|
bool splitIntoTokenAndRest(const std::string &str, std::string &token, std::string &rest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for intersection in positive direction of a ray.
|
||||||
|
* TODO: support inside?
|
||||||
|
*/
|
||||||
|
class IntersectionTest {
|
||||||
|
public:
|
||||||
|
IntersectionTest();
|
||||||
|
|
||||||
|
// creates a valid intersection point at distance d
|
||||||
|
IntersectionTest(float d);
|
||||||
|
|
||||||
|
// intersection distance
|
||||||
|
float distance() const;
|
||||||
|
|
||||||
|
glm::vec3 pointAtDistance(float d);
|
||||||
|
|
||||||
|
// returns true if there's an interseciton.
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
// return true if there's an intersection. then intersectionPoint is filled
|
||||||
|
// with details.
|
||||||
|
bool raySphere(
|
||||||
|
const glm::vec3 &rayPos, const glm::vec3 &rayDir,
|
||||||
|
const glm::vec3 &spherePos, float sphereRadius);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_valid;
|
||||||
|
float m_distance;
|
||||||
|
glm::vec3 m_rayPos;
|
||||||
|
glm::vec3 m_rayDir;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
|
|
||||||
for i in range(100):
|
|
||||||
a = random.randint(0, 360)
|
|
||||||
print("spawn #%d +shoot %d" % (i, a))
|
|
||||||
os.system("echo %d | ncat 192.168.0.191 3490" % a)
|
|
||||||
|
|
25
test/shoot_n_times.py
Executable file
25
test/shoot_n_times.py
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
|
||||||
|
delay = 0.1
|
||||||
|
|
||||||
|
if len(sys.argv) <= 1:
|
||||||
|
print("usage: ./prog $NUM_SHOOTS [$FLOAT_DELAY_BETWEEN_SHOTS]")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
delay = float(sys.argv[2])
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.connect(("192.168.0.191", 3490))
|
||||||
|
|
||||||
|
for i in range(int(sys.argv[1])):
|
||||||
|
a = random.randint(0, 360)
|
||||||
|
msg = str(a) + " \r\n"
|
||||||
|
s.send(msg.encode())
|
||||||
|
time.sleep(delay)
|
||||||
|
|
Loading…
Reference in a new issue