Also added some 3D helper objects.
"${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/3d_renderer.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/constants.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/obj.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/v3.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/v3_conv.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/qm.cc"
)
set(RPSDuelNative_HEADERS
"${CMAKE_CURRENT_SOURCE_DIR}/src/game_renderer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/basic_renderer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/3d_renderer.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/obj.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/v3.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/v3_conv.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/qm.h"
)
add_executable(RPSDuelNative ${RPSDuelNative_SOURCES})
--- /dev/null
+#include "obj.h"
+
+Object3D::Object3D(Model *model)
+ : pos{0.0F, 0.0F, 0.0F}, color{255, 255, 255, 255}, model(model) {}
+
+Object3D::~Object3D() {}
+
+const V3 &Object3D::get_pos() const { return pos; }
+
+void Object3D::set_pos(const V3 &pos) { this->pos = pos; }
+
+void Object3D::set_pos(V3 &&pos) { this->pos = std::forward<V3>(pos); }
+
+void Object3D::set_pos_x(float x) { pos[0] = x; }
+
+void Object3D::set_pos_y(float y) { pos[1] = y; }
+
+void Object3D::set_pos_z(float z) { pos[2] = z; }
+
+const VC4 &Object3D::get_color() const { return color; }
+
+void Object3D::set_color(const VC4 &color) { this->color = color; }
+
+void Object3D::set_color(VC4 &&color) {
+ this->color = std::forward<VC4>(color);
+}
+
+void Object3D::set_color_r(unsigned char r) { color[0] = r; }
+
+void Object3D::set_color_g(unsigned char g) { color[1] = g; }
+
+void Object3D::set_color_b(unsigned char b) { color[2] = b; }
+
+void Object3D::set_color_a(unsigned char a) { color[3] = a; }
--- /dev/null
+#ifndef ROCK_PAPER_SCISSORS_3D_OBJECT_BASE_H_
+#define ROCK_PAPER_SCISSORS_3D_OBJECT_BASE_H_
+
+// local includes
+#include "v3.h"
+
+// forward declarations
+struct Model;
+
+class Object3D {
+ public:
+ Object3D(Model *model);
+ virtual ~Object3D();
+
+ virtual void update(float dt) = 0;
+ virtual void draw() = 0;
+
+ const V3 &get_pos() const;
+ void set_pos(const V3 &pos);
+ void set_pos(V3 &&pos);
+ void set_pos_x(float x);
+ void set_pos_y(float y);
+ void set_pos_z(float z);
+
+ const VC4 &get_color() const;
+ void set_color(const VC4 &color);
+ void set_color(VC4 &&color);
+ void set_color_r(unsigned char r);
+ void set_color_g(unsigned char g);
+ void set_color_b(unsigned char b);
+ void set_color_a(unsigned char a);
+
+ protected:
+ V3 pos;
+ VC4 color;
+ Model *model;
+};
+
+#endif
--- /dev/null
+#include "qm.h"
+
+#ifdef __EMSCRIPTEN__
+#include "../ems.h"
+#else
+#include <random>
+#endif
+
+// standard library includes
+#include <cmath>
+
+// local includes
+#include "../constants.h"
+#include "v3_conv.h"
+
+QuestionMark::QuestionMark(Model *m)
+ : Object3D(m)
+#ifndef __EMSCRIPTEN__
+ ,
+ re(std::random_device{}())
+#endif
+{
+ randomize_timer_values();
+}
+
+QuestionMark::~QuestionMark() {}
+
+void QuestionMark::update(float dt) {
+ angle_timer -= dt;
+ if (angle_timer <= 0.0F) {
+#ifdef __EMSCRIPTEN__
+ angle_timer_max =
+ QM_ANGLE_TIMER_MAX + QM_ANGLE_TIMER_VARIANCE * call_js_get_random();
+#else
+ angle_timer_max = QM_ANGLE_TIMER_MAX +
+ QM_ANGLE_TIMER_VARIANCE *
+ std::uniform_real_distribution<float>(0.0F, 1.0F)(re);
+#endif
+ angle_timer += angle_timer_max;
+ }
+
+ y_timer -= dt;
+ if (y_timer <= 0.0F) {
+#ifdef __EMSCRIPTEN__
+ y_timer_max = QM_Y_TIMER_MAX + QM_Y_TIMER_VARIANCE * call_js_get_random();
+#else
+ y_timer_max = QM_Y_TIMER_MAX +
+ QM_Y_TIMER_VARIANCE *
+ std::uniform_real_distribution<float>(0.0F, 1.0F)(re);
+#endif
+ y_timer += y_timer_max;
+ }
+}
+
+void QuestionMark::draw() {
+ Vector3 unit{1.0F, 1.0F, 1.0F};
+ Vector3 vec3pos = V3ToRV3(pos);
+ float angle = angle_timer / angle_timer_max * 2.0F - 1.0F;
+ angle = angle >= 0.0F ? (std::cos(PI_F * angle) * QM_MAX_ANGLE_OFFSET)
+ : (std::cos(PI_F * (-angle)) * QM_MAX_ANGLE_OFFSET);
+ float offset = (y_timer / y_timer_max) * 2.0F - 1.0F;
+ offset = offset >= 0.0F
+ ? ((std::cos(PI_F * offset) + 1.0F) / 2.0F * QM_MAX_Y_OFFSET)
+ : ((std::cos(PI_F * (-offset)) + 1.0F) / 2.0F * QM_MAX_Y_OFFSET);
+ vec3pos.y += offset;
+ DrawModelEx(*model, vec3pos, {0.0F, 1.0F, 0.0F}, angle, unit, VC4ToC(color));
+}
+
+void QuestionMark::randomize_timer_values() {
+#ifdef __EMSCRIPTEN__
+ angle_timer = call_js_get_random() * QM_ANGLE_TIMER_MAX;
+ y_timer = call_js_get_random() * QM_Y_TIMER_MAX;
+#else
+ angle_timer =
+ std::uniform_real_distribution<float>(0.0F, QM_ANGLE_TIMER_MAX)(re);
+ y_timer = std::uniform_real_distribution<float>(0.0F, QM_Y_TIMER_MAX)(re);
+#endif
+ angle_timer_max = QM_ANGLE_TIMER_MAX;
+ y_timer_max = QM_Y_TIMER_MAX;
+}
--- /dev/null
+#ifndef ROCK_PAPER_SCISSORS_3D_QUESTION_MARK_H_
+#define ROCK_PAPER_SCISSORS_3D_QUESTION_MARK_H_
+
+#include "obj.h"
+
+#ifndef __EMSCRIPTEN__
+#include <random>
+#endif
+
+class QuestionMark : public Object3D {
+ public:
+ QuestionMark(Model *m);
+ ~QuestionMark() override;
+
+ void update(float dt) override;
+ void draw() override;
+
+ private:
+ void randomize_timer_values();
+
+#ifndef __EMSCRIPTEN__
+ std::default_random_engine re;
+#endif
+ float angle_timer;
+ float angle_timer_max;
+ float y_timer;
+ float y_timer_max;
+};
+
+#endif
--- /dev/null
+#include "v3.h"
+
+V3 operator+(const V3 &a, const V3 &b) {
+ return V3{a[0] + b[0], a[1] + b[1], a[2] + b[2]};
+}
+
+V3 operator-(const V3 &a, const V3 &b) {
+ return V3{a[0] - b[0], a[1] - b[1], a[2] - b[2]};
+}
+
+V3 operator*(const V3 &v, float s) { return V3{v[0] * s, v[1] * s, v[2] * s}; }
+
+V3 operator/(const V3 &v, float s) { return V3{v[0] / s, v[1] / s, v[2] / s}; }
+
+float V3F::dotp(const V3 &a, const V3 &b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+V3 V3F::crossp(const V3 &a, const V3 &b) {
+ return V3{a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
+ a[0] * b[1] - a[1] * b[0]};
+}
--- /dev/null
+#ifndef ROCK_PAPER_SCISSORS_3D_V3_H_
+#define ROCK_PAPER_SCISSORS_3D_V3_H_
+
+#include <array>
+
+using V3 = std::array<float, 3>;
+
+V3 operator+(const V3 &a, const V3 &b);
+V3 operator-(const V3 &a, const V3 &b);
+
+V3 operator*(const V3 &v, float s);
+V3 operator/(const V3 &v, float s);
+
+using VC3 = std::array<unsigned char, 3>;
+using VC4 = std::array<unsigned char, 4>;
+
+namespace V3F {
+extern float dotp(const V3 &a, const V3 &b);
+extern V3 crossp(const V3 &a, const V3 &b);
+} // namespace V3F
+
+#endif
--- /dev/null
+#include "v3_conv.h"
+
+Vector3 V3ToRV3(const V3 &v) { return Vector3{v[0], v[1], v[2]}; }
+
+V3 RV3ToV3(const Vector3 &v) { return V3{v.x, v.y, v.z}; }
+
+Color VC4ToC(const VC4 &v) { return Color{v[0], v[1], v[2], v[3]}; }
+
+VC4 CToVC4(const Color &c) { return VC4{c.r, c.g, c.b, c.a}; }
--- /dev/null
+#ifndef ROCK_PAPER_SCISSORS_3D_V3_CONF_H_
+#define ROCK_PAPER_SCISSORS_3D_V3_CONF_H_
+
+#include "v3.h"
+
+// third party includes
+#include <raylib.h>
+
+extern Vector3 V3ToRV3(const V3 &v);
+extern V3 RV3ToV3(const Vector3 &v);
+
+extern Color VC4ToC(const VC4 &v);
+extern VC4 CToVC4(const Color &c);
+
+#endif
#include "helpers.h"
Renderer3D::Renderer3D()
- : p1_pos{-1.0F, 0.0F, 0.0F},
+ : qms{QuestionMark(&qm_model), QuestionMark(&qm_model)},
+ qm_model(LoadModel("resources/question_mark.obj")),
+ p1_pos{-1.0F, 0.0F, 0.0F},
p2_pos{1.0F, 0.0F, 0.0F},
overview_timer(OVERVIEW_TIMER_MAX) {
camera.position.x = 0.0F;
skybox_model = LoadModel("resources/skybox.obj");
platform_model = LoadModel("resources/platform.obj");
- qm_model = LoadModel("resources/question_mark.obj");
+ // qm_model = LoadModel("resources/question_mark.obj");
rock_model = LoadModel("resources/rock.obj");
paper_model = LoadModel("resources/paper.obj");
scissors_model = LoadModel("resources/scissors.obj");
flags.set(1);
flags.set(4);
flags.set(5);
+
+ qms.at(0).set_pos({-1.0F, 0.0F, 0.0F});
+ qms.at(0).set_color_g(0);
+ qms.at(0).set_color_b(0);
+ qms.at(1).set_pos({1.0F, 0.0F, 0.0F});
+ qms.at(1).set_color_r(0);
+ qms.at(1).set_color_g(0);
}
Renderer3D::~Renderer3D() {
}
UpdateCamera(&camera);
+
+ for (auto &obj : qms) {
+ obj.update(dt);
+ }
}
void Renderer3D::draw_impl() {
BeginMode3D(camera);
DrawModel(skybox_model, root_pos, 1.0F, WHITE);
DrawModel(platform_model, root_pos, 1.0F, WHITE);
- DrawModel(qm_model, {-5.0F, 0.0F, 0.0F}, 1.0F, RED);
- DrawModel(qm_model, {5.0F, 0.0F, 0.0F}, 1.0F, BLUE);
- DrawModel(rock_model, p1_pos, 1.0F, WHITE);
- DrawModel(paper_model, p2_pos, 1.0F, WHITE);
- DrawModel(scissors_model, {-3.0F, 0.0F, 0.0F}, 1.0F, WHITE);
- DrawModel(scissors_model, {3.0F, 0.0F, 0.0F}, 1.0F, WHITE);
+ // DrawModel(qm_model, {-5.0F, 0.0F, 0.0F}, 1.0F, RED);
+ // DrawModel(qm_model, {5.0F, 0.0F, 0.0F}, 1.0F, BLUE);
+ // DrawModel(rock_model, p1_pos, 1.0F, WHITE);
+ // DrawModel(paper_model, p2_pos, 1.0F, WHITE);
+ // DrawModel(scissors_model, {-3.0F, 0.0F, 0.0F}, 1.0F, WHITE);
+ // DrawModel(scissors_model, {3.0F, 0.0F, 0.0F}, 1.0F, WHITE);
+ for (auto &obj : qms) {
+ obj.draw();
+ }
EndMode3D();
DrawText("Testing...", 0, 0, 20, RAYWHITE);
EndDrawing();
// third party includes
#include <raylib.h>
+// local includes
+#include "3d/qm.h"
+
class Renderer3D : public GameRenderer {
public:
Renderer3D();
void update_impl();
void draw_impl();
+ std::array<QuestionMark, 2> qms;
+
Camera camera;
Texture2D skybox_texture;
constexpr float OVERVIEW_ORBIT_Y = 7.0F;
constexpr float OVERVIEW_ORBIT_MODIFIER = 0.9F;
+// src/3D/
+
+constexpr float QM_ANGLE_TIMER_VARIANCE = 2.0F;
+constexpr float QM_Y_TIMER_VARIANCE = 2.0F;
+constexpr float QM_MAX_ANGLE_OFFSET = 30.0F;
+constexpr float QM_MAX_Y_OFFSET = 0.3F;
+constexpr float QM_ANGLE_TIMER_MAX = 5.0F;
+constexpr float QM_Y_TIMER_MAX = 3.5F;
+
#endif
../src/basic_renderer.cc \
../src/helpers.cc \
../src/3d_renderer.cc \
- ../src/constants.cc
+ ../src/constants.cc \
+ ../src/3d/obj.cc \
+ ../src/3d/v3.cc \
+ ../src/3d/v3_conv.cc \
+ ../src/3d/qm.cc
HEADERS = \
../src/constants.h \
../src/basic_renderer.h \
../src/helpers.h \
../src/game_renderer.h \
- ../src/3d_renderer.h
+ ../src/3d_renderer.h \
+ ../src/3d/obj.h \
+ ../src/3d/v3.h \
+ ../src/3d/v3_conv.h \
+ ../src/3d/qm.h
CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++