diff --git a/COMPILING b/COMPILING new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..f6a6148 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to produce Makefile.in +SUBDIRS = src/ + +EXTRA_DIST = icons/button_f10.png \ + icons/button_f7.png \ + icons/button_f8.png \ + icons/button_f9.png \ + icons/cam_external.png \ + icons/cam_front.png \ + icons/cam_rear.png \ + icons/cpanel.png \ + icons/cpan_f2_map.png \ + icons/cpan_f2_normal.png \ + icons/object_brown_dwarf.png \ + icons/object_planet_dwarf.png \ + icons/object_planet_large_gas_giant.png \ + icons/object_planet_medium_gas_giant.png \ + icons/object_planet_small_gas_giant.png \ + icons/object_planet_small.png \ + icons/object_planet_life.png \ + icons/object_star_a.png \ + icons/object_star_b.png \ + icons/object_star_f.png \ + icons/object_star_g.png \ + icons/object_star_k.png \ + icons/object_star_m.png \ + icons/object_star_o.png \ + icons/sectorview_f6_systeminfo.png \ + icons/timeaccel0_on.png \ + icons/timeaccel0.png \ + icons/timeaccel1_on.png \ + icons/timeaccel1.png \ + icons/timeaccel2_on.png \ + icons/timeaccel2.png \ + icons/timeaccel3_on.png \ + icons/timeaccel3.png \ + icons/timeaccel4_on.png \ + icons/timeaccel4.png \ + icons/zoom_in_f7.png \ + icons/zoom_out_f8.png \ + icons/hyperspace_f8.png \ + icons/comms_f4.png \ + icons/sysview_accel_f1_on.png icons/sysview_accel_f1.png icons/sysview_accel_f2_on.png icons/sysview_accel_f2.png icons/sysview_accel_f3_on.png icons/sysview_accel_f3.png icons/sysview_accel_r1_on.png icons/sysview_accel_r1.png icons/sysview_accel_r2_on.png icons/sysview_accel_r2.png icons/sysview_accel_r3_on.png icons/sysview_accel_r3.png \ + config.ini + + diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..185518e --- /dev/null +++ b/bootstrap @@ -0,0 +1,4 @@ +#! /bin/sh + +autoreconf -fvi + diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..1baeef9 --- /dev/null +++ b/config.ini @@ -0,0 +1,6 @@ +ScrWidth=800 +ScrHeight=600 +# 16 or 32. +ScrDepth=16 +StartFullscreen=0 + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..07494ad --- /dev/null +++ b/configure.ac @@ -0,0 +1,36 @@ +# Process this file with autoconf to create configure. + +AC_PREREQ(2.59) + +AC_INIT([Lephisto3D], [0.0.1], [allanis.saracraft.studios@gmail.com]) +#AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.9 foreign]) + +AC_PROG_CC +AC_PROG_CXX +AC_C_CONST +AC_PROG_RANLIB +#AC_PROG_LIBTOOL + +#AM_PATH_LIB3DS([1.2.0]) +#CFLAGS="$CFLAGS $LIB3DS_CFLAGS" +#LIBS="$LIBS $LIB3DS_LIBS" + +CFLAGS="-g -O2 -Wall" + +CFLAGS="$CFLAGS `pkg-config --cflags sigc++-2.0`" +LIBS="$LIBS `pkg-config --libs sigc++-2.0` -lGL -lGLU" +CFLAGS="$CFLAGS `pkg-config --cflags freetype2`" +LIBS="$LIBS `pkg-config --libs freetype2`" +CFLAGS="$CFLAGS `ode-config --cflags`" +LIBS="$LIBS `ode-config --libs`" + +PKG_CHECK_MODULES(SDL, sdl) +CFLAGS="$CFLAGS $SDL_CFLAGS" +LIBS="$LIBS $SDL_LIBS -lSDL_image" + +CXXFLAGS="$CFLAGS" + +AC_CONFIG_FILES([Makefile src/Makefile src/sbre/Makefile]) +AC_OUTPUT diff --git a/icons/button_f10.png b/icons/button_f10.png new file mode 100644 index 0000000..d989bfc Binary files /dev/null and b/icons/button_f10.png differ diff --git a/icons/button_f7.png b/icons/button_f7.png new file mode 100644 index 0000000..723c689 Binary files /dev/null and b/icons/button_f7.png differ diff --git a/icons/button_f8.png b/icons/button_f8.png new file mode 100644 index 0000000..09a5aa7 Binary files /dev/null and b/icons/button_f8.png differ diff --git a/icons/button_f9.png b/icons/button_f9.png new file mode 100644 index 0000000..42de524 Binary files /dev/null and b/icons/button_f9.png differ diff --git a/icons/cam_external.png b/icons/cam_external.png new file mode 100644 index 0000000..7c42431 Binary files /dev/null and b/icons/cam_external.png differ diff --git a/icons/cam_front.png b/icons/cam_front.png new file mode 100644 index 0000000..3496f31 Binary files /dev/null and b/icons/cam_front.png differ diff --git a/icons/cam_rear.png b/icons/cam_rear.png new file mode 100644 index 0000000..85b882b Binary files /dev/null and b/icons/cam_rear.png differ diff --git a/icons/comms_f4.png b/icons/comms_f4.png new file mode 100644 index 0000000..2bc8a34 Binary files /dev/null and b/icons/comms_f4.png differ diff --git a/icons/cpan_f2_map.png b/icons/cpan_f2_map.png new file mode 100644 index 0000000..ea0eb65 Binary files /dev/null and b/icons/cpan_f2_map.png differ diff --git a/icons/cpan_f2_normal.png b/icons/cpan_f2_normal.png new file mode 100644 index 0000000..a791b57 Binary files /dev/null and b/icons/cpan_f2_normal.png differ diff --git a/icons/cpanel.png b/icons/cpanel.png new file mode 100644 index 0000000..fab6461 Binary files /dev/null and b/icons/cpanel.png differ diff --git a/icons/hyperspace_f8.png b/icons/hyperspace_f8.png new file mode 100644 index 0000000..badcc43 Binary files /dev/null and b/icons/hyperspace_f8.png differ diff --git a/icons/object_brown_dwarf.png b/icons/object_brown_dwarf.png new file mode 100644 index 0000000..75cb10d Binary files /dev/null and b/icons/object_brown_dwarf.png differ diff --git a/icons/object_planet_dwarf.png b/icons/object_planet_dwarf.png new file mode 100644 index 0000000..9e8cfdc Binary files /dev/null and b/icons/object_planet_dwarf.png differ diff --git a/icons/object_planet_large_gas_giant.png b/icons/object_planet_large_gas_giant.png new file mode 100644 index 0000000..bb2d8d1 Binary files /dev/null and b/icons/object_planet_large_gas_giant.png differ diff --git a/icons/object_planet_life.png b/icons/object_planet_life.png new file mode 100644 index 0000000..6973b38 Binary files /dev/null and b/icons/object_planet_life.png differ diff --git a/icons/object_planet_medium_gas_giant.png b/icons/object_planet_medium_gas_giant.png new file mode 100644 index 0000000..108c35b Binary files /dev/null and b/icons/object_planet_medium_gas_giant.png differ diff --git a/icons/object_planet_small.png b/icons/object_planet_small.png new file mode 100644 index 0000000..41c5b1e Binary files /dev/null and b/icons/object_planet_small.png differ diff --git a/icons/object_planet_small_gas_giant.png b/icons/object_planet_small_gas_giant.png new file mode 100644 index 0000000..e94ca63 Binary files /dev/null and b/icons/object_planet_small_gas_giant.png differ diff --git a/icons/object_star_a.png b/icons/object_star_a.png new file mode 100644 index 0000000..256f3d3 Binary files /dev/null and b/icons/object_star_a.png differ diff --git a/icons/object_star_b.png b/icons/object_star_b.png new file mode 100644 index 0000000..470872e Binary files /dev/null and b/icons/object_star_b.png differ diff --git a/icons/object_star_f.png b/icons/object_star_f.png new file mode 100644 index 0000000..6f5b90e Binary files /dev/null and b/icons/object_star_f.png differ diff --git a/icons/object_star_g.png b/icons/object_star_g.png new file mode 100644 index 0000000..c96ad34 Binary files /dev/null and b/icons/object_star_g.png differ diff --git a/icons/object_star_k.png b/icons/object_star_k.png new file mode 100644 index 0000000..eb40de2 Binary files /dev/null and b/icons/object_star_k.png differ diff --git a/icons/object_star_m.png b/icons/object_star_m.png new file mode 100644 index 0000000..97332dc Binary files /dev/null and b/icons/object_star_m.png differ diff --git a/icons/object_star_o.png b/icons/object_star_o.png new file mode 100644 index 0000000..105f1a0 Binary files /dev/null and b/icons/object_star_o.png differ diff --git a/icons/sectorview_f6_systeminfo.png b/icons/sectorview_f6_systeminfo.png new file mode 100644 index 0000000..c789f96 Binary files /dev/null and b/icons/sectorview_f6_systeminfo.png differ diff --git a/icons/sysview_accel_f1.png b/icons/sysview_accel_f1.png new file mode 100644 index 0000000..0213f25 Binary files /dev/null and b/icons/sysview_accel_f1.png differ diff --git a/icons/sysview_accel_f1_on.png b/icons/sysview_accel_f1_on.png new file mode 100644 index 0000000..6fdd6fb Binary files /dev/null and b/icons/sysview_accel_f1_on.png differ diff --git a/icons/sysview_accel_f2.png b/icons/sysview_accel_f2.png new file mode 100644 index 0000000..fec8f9b Binary files /dev/null and b/icons/sysview_accel_f2.png differ diff --git a/icons/sysview_accel_f2_on.png b/icons/sysview_accel_f2_on.png new file mode 100644 index 0000000..e63144f Binary files /dev/null and b/icons/sysview_accel_f2_on.png differ diff --git a/icons/sysview_accel_f3.png b/icons/sysview_accel_f3.png new file mode 100644 index 0000000..abdb360 Binary files /dev/null and b/icons/sysview_accel_f3.png differ diff --git a/icons/sysview_accel_f3_on.png b/icons/sysview_accel_f3_on.png new file mode 100644 index 0000000..f55ca40 Binary files /dev/null and b/icons/sysview_accel_f3_on.png differ diff --git a/icons/sysview_accel_r1.png b/icons/sysview_accel_r1.png new file mode 100644 index 0000000..c4c954b Binary files /dev/null and b/icons/sysview_accel_r1.png differ diff --git a/icons/sysview_accel_r1_on.png b/icons/sysview_accel_r1_on.png new file mode 100644 index 0000000..86828fa Binary files /dev/null and b/icons/sysview_accel_r1_on.png differ diff --git a/icons/sysview_accel_r2.png b/icons/sysview_accel_r2.png new file mode 100644 index 0000000..5c3a675 Binary files /dev/null and b/icons/sysview_accel_r2.png differ diff --git a/icons/sysview_accel_r2_on.png b/icons/sysview_accel_r2_on.png new file mode 100644 index 0000000..a5f39fa Binary files /dev/null and b/icons/sysview_accel_r2_on.png differ diff --git a/icons/sysview_accel_r3.png b/icons/sysview_accel_r3.png new file mode 100644 index 0000000..ef10848 Binary files /dev/null and b/icons/sysview_accel_r3.png differ diff --git a/icons/sysview_accel_r3_on.png b/icons/sysview_accel_r3_on.png new file mode 100644 index 0000000..976fecf Binary files /dev/null and b/icons/sysview_accel_r3_on.png differ diff --git a/icons/timeaccel0.png b/icons/timeaccel0.png new file mode 100644 index 0000000..60be13b Binary files /dev/null and b/icons/timeaccel0.png differ diff --git a/icons/timeaccel0_on.png b/icons/timeaccel0_on.png new file mode 100644 index 0000000..82609ea Binary files /dev/null and b/icons/timeaccel0_on.png differ diff --git a/icons/timeaccel1.png b/icons/timeaccel1.png new file mode 100644 index 0000000..fc12578 Binary files /dev/null and b/icons/timeaccel1.png differ diff --git a/icons/timeaccel1_on.png b/icons/timeaccel1_on.png new file mode 100644 index 0000000..d48f188 Binary files /dev/null and b/icons/timeaccel1_on.png differ diff --git a/icons/timeaccel2.png b/icons/timeaccel2.png new file mode 100644 index 0000000..6ccb2e6 Binary files /dev/null and b/icons/timeaccel2.png differ diff --git a/icons/timeaccel2_on.png b/icons/timeaccel2_on.png new file mode 100644 index 0000000..efa407d Binary files /dev/null and b/icons/timeaccel2_on.png differ diff --git a/icons/timeaccel3.png b/icons/timeaccel3.png new file mode 100644 index 0000000..2ac3f3a Binary files /dev/null and b/icons/timeaccel3.png differ diff --git a/icons/timeaccel3_on.png b/icons/timeaccel3_on.png new file mode 100644 index 0000000..bea687b Binary files /dev/null and b/icons/timeaccel3_on.png differ diff --git a/icons/timeaccel4.png b/icons/timeaccel4.png new file mode 100644 index 0000000..fbff550 Binary files /dev/null and b/icons/timeaccel4.png differ diff --git a/icons/timeaccel4_on.png b/icons/timeaccel4_on.png new file mode 100644 index 0000000..a4147bc Binary files /dev/null and b/icons/timeaccel4_on.png differ diff --git a/icons/zoom_in_f7.png b/icons/zoom_in_f7.png new file mode 100644 index 0000000..3f9618b Binary files /dev/null and b/icons/zoom_in_f7.png differ diff --git a/icons/zoom_out_f8.png b/icons/zoom_out_f8.png new file mode 100644 index 0000000..d341cce Binary files /dev/null and b/icons/zoom_out_f8.png differ diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..377397f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,19 @@ +## Process this file with automake to produce Makefile.in +SUBDIRS = sbre/ + +bin_PROGRAMS = Lephisto3D +Lephisto3D_SOURCES = main.cpp gui_button.cpp gui.cpp gui_fixed.cpp gui_screen.cpp gui_label.cpp glfreetype.cpp \ + objimport.cpp body.cpp space.cpp ship.cpp player.cpp gui_toggle_button.cpp gui_radio_button.cpp \ + gui_radio_group.cpp rigid_body.cpp planet.cpp star.cpp frame.cpp gui_image_button.cpp gui_image.cpp \ + gui_image_radio_button.cpp gui_multi_state_image_button.cpp ship_cpanel.cpp gui_widget.cpp sector_view.cpp \ + mtrand.cpp world_view.cpp system_view.cpp star_system.cpp sector.cpp system_info_view.cpp generic_system_view.cpp \ + gui_container.cpp date.cpp space_station.cpp space_station_view.cpp static_rigid_body.cpp ship_type.cpp +Lephisto3D_LDADD = sbre/libsbre.a + +include_HEADERS = body.h frame.h generic_system_view.h glfreetype.h gui_button.h gui_container.h gui_events.h gui_fixed.h \ + gui.h gui_image_button.h gui_image.h gui_image_radio_button.h gui_label.h gui_multi_state_image_button.h gui_radio_button.h \ + gui_radio_group.h gui_screen.h gui_toggle_button.h gui_widget.h libs.h matrix4x4.h mtrand.h objimport.h l3d.h \ + planet.h player.h rigid_body.h sector.h sector_view.h ship_cpanel.h ship.h space.h star.h star_system.h system_info_view.h \ + system_view.h vector3.h view.h world_view.h date.h space_station.h space_station_view.h static_rigid_body.h gui_iselectable.h \ + ship_type.h object.h + diff --git a/src/body.cpp b/src/body.cpp new file mode 100644 index 0000000..77b338e --- /dev/null +++ b/src/body.cpp @@ -0,0 +1,14 @@ +#include "libs.h" +#include "body.h" +#include "frame.h" + +Body::Body(void) { + m_frame = 0; + m_flags = 0; +} + +/* f == NULL, then absolute position within system. */ +vector3d Body::GetPositionRelTo(const Frame* relTo) { + return m_frame->GetPosRelativeToOtherFrame(relTo) + GetPosition(); +} + diff --git a/src/body.h b/src/body.h new file mode 100644 index 0000000..4f8ca3d --- /dev/null +++ b/src/body.h @@ -0,0 +1,40 @@ +#pragma once +#include + +#include "vector3.h" +#include "matrix4x4.h" +#include "object.h" + +class Frame; +class ObjMesh; + +class Body: public Object { +public: + Body(void); + virtual ~Body(void) { }; + virtual Object::Type GetType(void) { return Object::BODY; } + virtual void SetPosition(vector3d p) = 0; + virtual vector3d GetPosition(void) = 0; /* Within frame. */ + vector3d GetPositionRelTo(const Frame*); + virtual void Render(const Frame* camFrame) = 0; + virtual void TransformToModelCoords(const Frame* camFrame) = 0; + virtual void TransformCameraTo(void) = 0; + virtual void SetFrame(Frame* f) { m_frame = f; } + Frame* GetFrame(void) { return m_frame; } + void SetLabel(const char* label) { m_label = label; } + std::string& GetLabel(void) { return m_label; } + unsigned int GetFlags(void) { return m_flags; } + /* Return true if we should apply damage. */ + virtual bool OnCollision(Body* b) { return false; } + + enum { FLAG_CAN_MOVE_FRAME = 1 }; + +protected: + unsigned int m_flags; + +private: + /* Frame of reference. */ + Frame* m_frame; + std::string m_label; +}; + diff --git a/src/date.cpp b/src/date.cpp new file mode 100644 index 0000000..56707ad --- /dev/null +++ b/src/date.cpp @@ -0,0 +1,77 @@ +#include "date.h" +#include +#include +#include "libs.h" + +/* Urgh... */ +static const char *i_am_a_little_teapot[365] = +{ "Jan 1","Jan 2","Jan 3","Jan 4","Jan 5","Jan 6","Jan 7", + "Jan 8","Jan 9","Jan 10","Jan 11","Jan 12","Jan 13","Jan 14", + "Jan 15","Jan 16","Jan 17","Jan 18","Jan 19","Jan 20","Jan 21", + "Jan 22","Jan 23","Jan 24","Jan 25","Jan 26","Jan 27","Jan 28", + "Jan 29","Jan 30","Jan 31","Feb 1","Feb 2","Feb 3","Feb 4", + "Feb 5","Feb 6","Feb 7","Feb 8","Feb 9","Feb 10","Feb 11","Feb 12", + "Feb 13","Feb 14","Feb 15","Feb 16","Feb 17","Feb 18","Feb 19", + "Feb 20","Feb 21","Feb 22","Feb 23","Feb 24","Feb 25","Feb 26", + "Feb 27","Feb 28","Mar 1","Mar 2","Mar 3","Mar 4","Mar 5","Mar 6", + "Mar 7","Mar 8","Mar 9","Mar 10","Mar 11","Mar 12","Mar 13", + "Mar 14","Mar 15","Mar 16","Mar 17","Mar 18","Mar 19","Mar 20", + "Mar 21","Mar 22","Mar 23","Mar 24","Mar 25","Mar 26","Mar 27", + "Mar 28","Mar 29","Mar 30","Mar 31","Apr 1","Apr 2","Apr 3", + "Apr 4","Apr 5","Apr 6","Apr 7","Apr 8","Apr 9","Apr 10","Apr 11", + "Apr 12","Apr 13","Apr 14","Apr 15","Apr 16","Apr 17","Apr 18", + "Apr 19","Apr 20","Apr 21","Apr 22","Apr 23","Apr 24","Apr 25", + "Apr 26","Apr 27","Apr 28","Apr 29","Apr 30","May 1","May 2", + "May 3","May 4","May 5","May 6","May 7","May 8","May 9","May 10", + "May 11","May 12","May 13","May 14","May 15","May 16","May 17", + "May 18","May 19","May 20","May 21","May 22","May 23","May 24", + "May 25","May 26","May 27","May 28","May 29","May 30","May 31", + "Jun 1","Jun 2","Jun 3","Jun 4","Jun 5","Jun 6","Jun 7","Jun 8", + "Jun 9","Jun 10","Jun 11","Jun 12","Jun 13","Jun 14","Jun 15", + "Jun 16","Jun 17","Jun 18","Jun 19","Jun 20","Jun 21","Jun 22", + "Jun 23","Jun 24","Jun 25","Jun 26","Jun 27","Jun 28","Jun 29", + "Jun 30","Jul 1","Jul 2","Jul 3","Jul 4","Jul 5","Jul 6","Jul 7", + "Jul 8","Jul 9","Jul 10","Jul 11","Jul 12","Jul 13","Jul 14", + "Jul 15","Jul 16","Jul 17","Jul 18","Jul 19","Jul 20","Jul 21", + "Jul 22","Jul 23","Jul 24","Jul 25","Jul 26","Jul 27","Jul 28", + "Jul 29","Jul 30","Jul 31","Aug 1","Aug 2","Aug 3","Aug 4","Aug 5", + "Aug 6","Aug 7","Aug 8","Aug 9","Aug 10","Aug 11","Aug 12", + "Aug 13","Aug 14","Aug 15","Aug 16","Aug 17","Aug 18","Aug 19", + "Aug 20","Aug 21","Aug 22","Aug 23","Aug 24","Aug 25","Aug 26", + "Aug 27","Aug 28","Aug 29","Aug 30","Aug 31","Sep 1","Sep 2", + "Sep 3","Sep 4","Sep 5","Sep 6","Sep 7","Sep 8","Sep 9","Sep 10", + "Sep 11","Sep 12","Sep 13","Sep 14","Sep 15","Sep 16","Sep 17", + "Sep 18","Sep 19","Sep 20","Sep 21","Sep 22","Sep 23","Sep 24", + "Sep 25","Sep 26","Sep 27","Sep 28","Sep 29","Sep 30","Oct 1", + "Oct 2","Oct 3","Oct 4","Oct 5","Oct 6","Oct 7","Oct 8","Oct 9", + "Oct 10","Oct 11","Oct 12","Oct 13","Oct 14","Oct 15","Oct 16", + "Oct 17","Oct 18","Oct 19","Oct 20","Oct 21","Oct 22","Oct 23", + "Oct 24","Oct 25","Oct 26","Oct 27","Oct 28","Oct 29","Oct 30", + "Oct 31","Nov 1","Nov 2","Nov 3","Nov 4","Nov 5","Nov 6","Nov 7", + "Nov 8","Nov 9","Nov 10","Nov 11","Nov 12","Nov 13","Nov 14", + "Nov 15","Nov 16","Nov 17","Nov 18","Nov 19","Nov 20","Nov 21", + "Nov 22","Nov 23","Nov 24","Nov 25","Nov 26","Nov 27","Nov 28", + "Nov 29","Nov 30","Dec 1","Dec 2","Dec 3","Dec 4","Dec 5","Dec 6", + "Dec 7","Dec 8","Dec 9","Dec 10","Dec 11","Dec 12","Dec 13", + "Dec 14","Dec 15","Dec 16","Dec 17","Dec 18","Dec 19","Dec 20", + "Dec 21","Dec 22","Dec 23","Dec 24","Dec 25","Dec 26","Dec 27", + "Dec 28","Dec 29","Dec 30","Dec 31" +}; + +int mod(int a, int b) { + int r = a%b; + return r >= 0 ? r : r*b; +} + +std::string date_format(double t) { + int year = floor(t/(60*60*24*365)); year += 3200; + int day = floor(t/(60*60*24)); day = mod(day, 365); + int hour = floor(t/(60*60)); hour = mod(hour, 24); + int min = floor(t/60); min = mod(min, 60); + int sec = mod(t, 60); + char buf[128]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d %s %d", hour, min, sec, + i_am_a_little_teapot[day], year); + return buf; +} + diff --git a/src/date.h b/src/date.h new file mode 100644 index 0000000..6d89cc3 --- /dev/null +++ b/src/date.h @@ -0,0 +1,5 @@ +#pragma once +#include + +std::string date_format(double time); + diff --git a/src/frame.cpp b/src/frame.cpp new file mode 100644 index 0000000..67ccb18 --- /dev/null +++ b/src/frame.cpp @@ -0,0 +1,55 @@ +#include "frame.h" +#include "space.h" + +Frame::Frame(void) { + Init(NULL, "", 0); +} + +Frame::Frame(Frame* parent, const char* label) { + Init(parent, label, 0); +} + +Frame::Frame(Frame* parent, const char* label, unsigned int flags) { + Init(parent, label, flags); +} + +void Frame::RemoveChild(Frame* f) { + m_children.remove(f); +} + +void Frame::Init(Frame* parent, const char* label, unsigned int flags) { + m_parent = parent; + m_flags = flags; + m_radius = 0; + m_dSpaceID = dHashSpaceCreate(0); + if(m_parent) { + m_parent->m_children.push_back(this); + } + if(label) m_label = label; +} + +Frame::~Frame(void) { + dSpaceDestroy(m_dSpaceID); + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) delete *i; +} + +vector3d Frame::GetFramePosRelativeToOther(const Frame* frame, const Frame* relTo) { + vector3d pos = vector3d(0,0,0); + + const Frame* f = frame; + const Frame* root = Space::GetRootFrame(); + + while((f!=root) && (relTo !=f)) { + pos += f->m_pos; + f = f->m_parent; + } + + /* Now pos is relative to root, or to desired frame. */ + while(relTo != f) { + pos -= relTo->m_pos; + relTo = relTo->m_parent; + } + + return pos; +} + diff --git a/src/frame.h b/src/frame.h new file mode 100644 index 0000000..555e65e --- /dev/null +++ b/src/frame.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include "libs.h" + +/* Frame of reference. */ +class Frame { +public: + Frame(void); + Frame(Frame* parent, const char* label); + Frame(Frame* parent, const char* label, unsigned int flags); + ~Frame(void); + + const char* GetLabel(void) { return m_label.c_str(); } + void SetLabel(const char* label) { m_label = label; } + void SetPosition(const vector3d &pos) { m_pos = pos; } + void SetRadius(double radius) { m_radius = radius; } + void RemoveChild(Frame* f); + void AddGeom(dGeomID g) { dSpaceAdd(m_dSpaceID, g); } + void RemoveGeom(dGeomID g) { dSpaceRemove(m_dSpaceID, g); } + dSpaceID GetSpaceID(void) { return m_dSpaceID; } + + static vector3d GetFramePosRelativeToOther(const Frame* frame, const Frame* relTo); + + vector3d GetPosRelativeToOtherFrame(const Frame* relTo) const { + return GetFramePosRelativeToOther(this, relTo); + } + + bool IsLocalPosInFrame(const vector3d& pos) { + return (pos.Length() < m_radius); + } + + /* If parent is null then frame position is absolute. */ + Frame* m_parent; + std::list m_children; + + enum { TEMP_VIEWING=1 }; + +private: + void Init(Frame* parent, const char* label, unsigned int flags); + vector3d m_pos; + std::string m_label; + double m_radius; + int m_flags; + dSpaceID m_dSpaceID; +}; + diff --git a/src/generic_system_view.cpp b/src/generic_system_view.cpp new file mode 100644 index 0000000..5021ccb --- /dev/null +++ b/src/generic_system_view.cpp @@ -0,0 +1,51 @@ +#include "l3d.h" +#include "generic_system_view.h" +#include "sector_view.h" + +GenericSystemView::GenericSystemView(void) : View() { + px = py = pidx = 0xdeadbeef; + m_scannerLayout = new Gui::Fixed(140, 2, 360, 60); + m_scannerLayout->SetTransparency(true); + + m_systemName = new Gui::Label(""); + m_systemName->SetColor(1, 1, 0); + m_scannerLayout->Add(m_systemName, 40, 44); + + m_distance = new Gui::Label(""); + m_distance->SetColor(1, 0, 0); + m_scannerLayout->Add(m_distance, 150, 44); + + m_starType = new Gui::Label(""); + m_starType->SetColor(1, 0, 1); + m_scannerLayout->Add(m_starType, 22, 26); + + m_shortDesc = new Gui::Label(""); + m_shortDesc->SetColor(1, 0, 1); + m_scannerLayout->Add(m_shortDesc, 5, 8); +} + +void GenericSystemView::Draw3D(void) { + StarSystem* s = L3D::GetSelectedSystem(); + + if(s && !s->IsSystem(px, py, pidx)) { + s->GetPos(&px, &py, &pidx); + + m_systemName->SetText(s->rootBody->name); + m_distance->SetText("Dist. XX.XX light years."); + m_starType->SetText(s->rootBody->GetAstroDescription()); + m_shortDesc->SetText("Short description of system"); + + onSelectedSystemChanged.emit(s); + } +} + +void GenericSystemView::ShowAll(void) { + View::ShowAll(); + if(m_scannerLayout) m_scannerLayout->ShowAll(); +} + +void GenericSystemView::HideAll(void) { + View::HideAll(); + if(m_scannerLayout) m_scannerLayout->HideAll(); +} + diff --git a/src/generic_system_view.h b/src/generic_system_view.h new file mode 100644 index 0000000..4d1c836 --- /dev/null +++ b/src/generic_system_view.h @@ -0,0 +1,25 @@ +#pragma once +#include "libs.h" +#include "gui.h" +#include "view.h" +#include "star_system.h" + +class SystemInfoScannerText; + +class GenericSystemView: public View { +public: + GenericSystemView(void); + virtual void Draw3D(void); + virtual void ShowAll(void); + virtual void HideAll(void); + sigc::signal onSelectedSystemChanged; + +private: + Gui::Fixed* m_scannerLayout; + Gui::Label* m_systemName; + Gui::Label* m_distance; + Gui::Label* m_starType; + Gui::Label* m_shortDesc; + int px, py, pidx; +}; + diff --git a/src/glfreetype.cpp b/src/glfreetype.cpp new file mode 100644 index 0000000..a5a1a3a --- /dev/null +++ b/src/glfreetype.cpp @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include "glfreetype.h" + +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_OUTLINE_H + +#ifdef _WIN32 +typedef GLvoid(APIENTRY* _GLUfuncptr)(void); +#endif + +FT_Library library; + +#include + +static GLUtesselator* tobj; + +static inline double fac(int n) { + double r = 1.0; + + for(int i = 2; i < n; i++) { + r *= (double)i; + } + return r; +} + +static inline double binomial_coeff(int n, int m) { + return fac(n)/(fac(m)*(fac(n-m))); +} + +static void eval_bezier(GLdouble* out, double t, int n_points, double* points) { + std::vector c(n_points); + + for(int i = 0; i < n_points; i++) { + c[i] = pow(1.0f-t, n_points-(i+1)) * pow(t, i) * + binomial_coeff(n_points-1, i); + } + + out[0] = out[1] = out[2] = 0; + + for(int i = 0; i < n_points; i++) { + out[0] += points[3*i] * c[i]; + out[1] += points[3*i+1] * c[i]; + out[2] += points[3*i+2] * c[i]; + } +} + +#define DIV 2048.0f + +bool GenContourPoints(int a_char, FT_Outline* a_outline, const int a_contour, + int a_bezierIters, std::vector* ao_points) { +#define push_point(__p) { \ + ao_points->push_back((__p)[0]); \ + ao_points->push_back((__p)[1]); \ + ao_points->push_back((__p)[2]); \ +} + + int cont = (a_contour-1 < 0 ? 0 : 1 + a_outline->contours[a_contour-1]); + + double point_buf[256][3]; + char point_type[256]; + int pos = 0; + + for(; cont <= a_outline->contours[a_contour]; cont++, pos++) { + point_type[pos] = a_outline->tags[cont]; + point_buf[pos][0] = a_outline->points[cont].x/DIV; + point_buf[pos][1] = a_outline->points[cont].y/DIV; + point_buf[pos][2] = 0; + } + if(!point_type[pos-1]) { + /* + * Need to duplicate first vertex if last + * section is a bezier. + */ + point_type[pos] = 1; + point_buf[pos][0] = point_buf[0][0]; + point_buf[pos][1] = point_buf[0][1]; + point_buf[pos][2] = 0; + pos++; + } + + int start = -1; + for(int k = 0; k < pos; k++) { + if(!(point_type[k] & 1)) continue; + + if(start == -1) { start = k; continue; } + + int len = 1+k-start; + /* Trace segment. */ + if(len == 2) { + /* Staight line. */ + push_point(point_buf[k-1]); + push_point(point_buf[k]); + } else { + /* Bezier. */ + double b_in[3][3]; + double v[3]; + + /* + * Truetype is all quadratic bezier, + * using average points between + * 'control points' as end points. + */ + + /* First bezier. */ + b_in[0][0] = point_buf[start][0]; + b_in[0][1] = point_buf[start][1]; + b_in[0][2] = 0; + + b_in[1][0] = point_buf[start+1][0]; + b_in[1][1] = point_buf[start+1][1]; + b_in[1][2] = 0; + + if(len > 3) { + b_in[2][0] = 0.5 * (point_buf[start+1][0] + point_buf[start+2][0]); + b_in[2][1] = 0.5 * (point_buf[start+1][1] + point_buf[start+2][1]); + b_in[2][2] = 0; + } else { + b_in[2][0] = point_buf[start+2][0]; + b_in[2][1] = point_buf[start+2][1]; + b_in[2][2] = 0; + } + + for(int l = 0; l <= a_bezierIters; l++) { + double t = (1.0/a_bezierIters)*l; + eval_bezier(v, t, 3, &b_in[0][0]); + v[2] = 0.0; + push_point(v); + } + + /* Middle beziers. */ + if(len > 4) { + for(int _p = 1; _p < len-3; _p++) { + b_in[0][0] = 0.5*(point_buf[start+_p][0]+point_buf[start+_p+1][0]); + b_in[0][1] = 0.5*(point_buf[start+_p][1]+point_buf[start+_p+1][1]); + + b_in[0][2] = 0; + + b_in[1][0] = point_buf[start+_p+1][0]; + b_in[1][1] = point_buf[start+_p+1][1]; + b_in[1][2] = 0; + + b_in[2][0] = 0.5*(point_buf[start+_p+1][0] + point_buf[start+_p+2][0]); + b_in[2][1] = 0.5*(point_buf[start+_p+1][1] + point_buf[start+_p+2][1]); + b_in[2][2] = 0; + + for(int l = 0; l <= a_bezierIters; l++) { + double t = (1.0/a_bezierIters)*l; + eval_bezier(v, t, 3, &b_in[0][0]); + v[2] = 0.0; + push_point(v); + } + } + } + + /* End. */ + if(len > 3) { + const int _p = start+len-3; + b_in[0][0] = 0.5 * (point_buf[_p][0] + point_buf[_p+1][0]); + b_in[0][1] = 0.5 * (point_buf[_p][1] + point_buf[_p+1][1]); + b_in[0][2] = 0; + + b_in[1][0] = point_buf[_p+1][0]; + b_in[1][1] = point_buf[_p+1][1]; + b_in[1][2] = 0; + + b_in[2][0] = point_buf[_p+2][0]; + b_in[2][1] = point_buf[_p+2][1]; + b_in[2][2] = 0; + + for(int l = 0; l <= a_bezierIters; l++) { + double t = (1.0/a_bezierIters)*l; + eval_bezier(v, t, 3, &b_in[0][0]); + v[2] = 0.0; + push_point(v); + } + } + } + start = k; + } + return true; +} + +#ifndef CALLBACK +# ifdef WIN32 +# define CALLBACK __attribute__ ((__stdcall__)) +# else +# define CALLBACK +# endif +#endif /* CALLBACK */ + +struct TessData { + std::vector* pts; /* Inputs, added by combine. */ + int numvtx; + + std::vector index; /* Output index list. */ + GLenum lasttype; + int state; /* 0, no vertices, 1, 1 vertex, 2, 2 or more. 0x4 => clockwise. */ + + Uint16 vtx[2]; +}; + +static Uint16 g_index[65536]; + +void CALLBACK beginCallback(GLenum which, GLvoid* poly_data) { + TessData* pData = (TessData*)poly_data; + pData->lasttype = which; + pData->state = 0; +} + +void CALLBACK errorCallback(GLenum errorCode) { + const GLubyte* estr; + + estr = gluErrorString(errorCode); + fprintf(stderr, "Tesserlation Error: %s\n", estr); +} + +void CALLBACK endCallback(void) { + +} + +void CALLBACK vertexCallback(GLvoid* vertex, GLvoid* poly_data) { + TessData* pData = (TessData*)poly_data; + Uint16 index = *(Uint16*)vertex; + switch(pData->lasttype) { + case GL_TRIANGLES: + pData->index.push_back(index); + break; + case GL_TRIANGLE_STRIP: + if((pData->state & 3) < 2) + pData->vtx[pData->state++] = index; + else { + pData->index.push_back(index); + if(pData->state & 0x4) { + pData->index.push_back(pData->vtx[1]); + pData->index.push_back(pData->vtx[0]); + } else { + pData->index.push_back(pData->vtx[0]); + pData->index.push_back(pData->vtx[1]); + } + pData->vtx[0] = pData->vtx[1]; + pData->vtx[1] = index; + pData->state ^= 0x4; + } + break; + case GL_TRIANGLE_FAN: + if((pData->state & 3) < 2) + pData->vtx[pData->state++] = index; + else { + pData->index.push_back(index); + pData->index.push_back(pData->vtx[0]); + pData->index.push_back(pData->vtx[1]); + pData->vtx[1] = index; + } + } +} + +void CALLBACK combineCallback(GLdouble coords[3], + GLdouble* vertex_data[4], + GLfloat weight[4], void** dataOut, void* poly_data) { + + TessData* pData = (TessData*)poly_data; + pData->pts->push_back(coords[0]); + pData->pts->push_back(coords[1]); + pData->pts->push_back(coords[2]); + *dataOut = (void*)&g_index[pData->numvtx++]; +} + +#define BEZIER_STEPS 2 + +void FontFace::RenderGlyph(int chr) { + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + glfglyph_t* glyph = &m_glyphs[chr]; + glVertexPointer(3, GL_FLOAT, 3*sizeof(float), glyph->varray); + glDrawElements(GL_TRIANGLES, glyph->numidx, GL_UNSIGNED_SHORT, glyph->iarray); +} + +void FontFace::RenderString(const char* str) { + glPushMatrix(); + for(unsigned int i = 0; i < strlen(str); i++) { + if(str[i] == '\n') { + glPopMatrix(); + glTranslatef(0, -m_height, 0); + glPushMatrix(); + } else { + glfglyph_t* glyph = &m_glyphs[str[i]]; + if(glyph->numidx) RenderGlyph(str[i]); + glTranslatef(glyph->advx, 0, 0); + } + } + glPopMatrix(); +} + +FontFace::FontFace(const char* filename_ttf) { + FT_Face face; + if(0 != FT_New_Face(library, filename_ttf, 0, &face)) { + fprintf(stderr, "Error: Couldn't load '%s'\n", filename_ttf); + } else { + FT_Set_Char_Size(face, 50*64, 0, 100, 0); + for(int chr = 32; chr < 127; chr++) { + if(0 != FT_Load_Char(face, chr, FT_LOAD_NO_SCALE)) { + printf("Couldn't load glyph\n"); + continue; + } + + assert(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE); + FT_Outline* outline = &face->glyph->outline; + + std::vector temppts; + std::vector indices; + std::vector pts; + int nv = 0; + + TessData tessdata; + tessdata.pts = &pts; + + gluTessNormal(tobj, 0, 0, 1); + gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + gluTessBeginPolygon(tobj, &tessdata); + for(int contour = 0; contour < outline->n_contours; contour++) { + gluTessBeginContour(tobj); + temppts.clear(); + GenContourPoints(chr, outline, contour, BEZIER_STEPS, &temppts); + for(size_t i = 0; i < temppts.size(); i++) pts.push_back(temppts[i]); + for(size_t i = 0; i < temppts.size(); i+=4, nv++) + gluTessVertex(tobj, &pts[nv*3], &g_index[nv]); + gluTessEndContour(tobj); + } + tessdata.numvtx = nv; + gluTessEndPolygon(tobj); + + glfglyph_t _face; + + nv = tessdata.numvtx; + _face.varray = (float*)malloc(nv*3*sizeof(float)); + for(int i = 0; i < nv*3; i++) _face.varray[i] = (float)pts[i]; + + _face.numidx = (int)tessdata.index.size(); + _face.iarray = (Uint16*)malloc(_face.numidx*sizeof(Uint16)); + for(int i = 0; i < _face.numidx; i++) _face.iarray[i] = tessdata.index[i]; + + _face.advx = face->glyph->linearHoriAdvance/(float)(1<<16)/72.0f; + _face.advy = face->glyph->linearVertAdvance/(float)(1<<16)/72.0f; + //printf(%f,%f\n", _face.advx, _face.advy); + m_glyphs[chr] = _face; + } + m_height = m_glyphs['M'].advy; + m_width = m_glyphs['M'].advx; + } +} + +void GLFTInit(void) { + if(0 != FT_Init_FreeType(&library)) { + printf("Couldn't init freetype library.\n"); + exit(0); + } + + tobj = gluNewTess(); + gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (_GLUfuncptr) vertexCallback); + gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (_GLUfuncptr) beginCallback); + gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr) endCallback); + gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr) errorCallback); + gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (_GLUfuncptr) combineCallback); + + for(Uint16 i = 0; i < 65535; i++) g_index[i] = i; +} diff --git a/src/glfreetype.h b/src/glfreetype.h new file mode 100644 index 0000000..7e1074a --- /dev/null +++ b/src/glfreetype.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +class FontFace { +public: + FontFace(const char* filename_ttf); + void RenderGlyph(int chr); + void RenderString(const char* str); + + /* Of Ms. */ + float GetHeight(void) { return m_height; } + float GetWidth(void) { return m_width; } + +private: + float m_height; + float m_width; + + struct glfglyph_t { + float* varray; + Uint16* iarray; + int numidx; + float advx, advy; + }; + std::map m_glyphs; +}; +void GLFTInit(void); + diff --git a/src/gui.cpp b/src/gui.cpp new file mode 100644 index 0000000..51217ad --- /dev/null +++ b/src/gui.cpp @@ -0,0 +1,46 @@ +#include "libs.h" +#include "gui.h" + +namespace Gui { +namespace RawEvents { + sigc::signal onMouseDown; + sigc::signal onMouseUp; + sigc::signal onKeyDown; + sigc::signal onKeyUp; +} + +namespace Color { + const float bg[] = { .25, .37, .63 }; + const float bgShadow[] = { .08, .12, .21 }; +} + +void HandleSDLEvent(SDL_Event* event) { + switch(event->type) { + case SDL_MOUSEBUTTONDOWN: + Screen::OnClick(&event->button); + RawEvents::onMouseDown.emit(&event->button); + break; + case SDL_MOUSEBUTTONUP: + Screen::OnClick(&event->button); + RawEvents::onMouseUp.emit(&event->button); + break; + case SDL_KEYDOWN: + Screen::OnKeyDown(&event->key.keysym); + RawEvents::onKeyDown.emit(&event->key); + break; + case SDL_KEYUP: + RawEvents::onKeyUp.emit(&event->key); + break; + } +} + +void Draw(void) { + Screen::Draw(); +} + +void Init(int screen_width, int screen_height, int ui_width, int ui_height) { + Screen::Init(screen_width, screen_height, ui_width, ui_height); +} + +} + diff --git a/src/gui_button.cpp b/src/gui_button.cpp new file mode 100644 index 0000000..05c22a0 --- /dev/null +++ b/src/gui_button.cpp @@ -0,0 +1,102 @@ +#include "libs.h" +#include "gui.h" + +#define BUTTON_SIZE 16 + +namespace Gui { + +Button::Button(void) { + m_isPressed = false; + m_eventMask = EVENT_MOUSEDOWN | EVENT_MOUSEUP; + SetSize(BUTTON_SIZE, BUTTON_SIZE); +} + +void Button::OnMouseDown(MouseButtonEvent* e) { + if(e->button == 1) { + m_isPressed = true; + onPress.emit(); + /* Wait for mouse release, regardless of where on screen. */ + _m_release = RawEvents::onMouseUp.connect(sigc::mem_fun(this, &Button::OnRawMouseUp)); + } +} + +void Button::OnMouseUp(MouseButtonEvent* e) { + if((e->button == 1) && m_isPressed) { + m_isPressed = false; + onClick.emit(); + } +} + +void Button::OnActivate(void) { + /* Activated by keyboard shortcut. */ + m_isPressed = true; + onPress.emit(); + _m_kbrelease = RawEvents::onKeyUp.connect(sigc::mem_fun(this, &Button::OnRawKeyUp)); +} + +void Button::OnRawKeyUp(SDL_KeyboardEvent* e) { + if(e->keysym.sym == m_shortcut.sym) { + m_isPressed = false; + onRelease.emit(); + onClick.emit(); + _m_kbrelease.disconnect(); + } +} + +void Button::OnRawMouseUp(SDL_MouseButtonEvent* e) { + if(e->button == 1) { + m_isPressed = false; + _m_release.disconnect(); + onRelease.emit(); + } +} + +void SolidButton::GetSizeRequested(float size[2]) { + size[0] = size[1] = BUTTON_SIZE; +} + +void TransparentButton::GetSizeRequested(float size[2]) { + size[0] = size[1] = BUTTON_SIZE; +} + +void SolidButton::Draw(void) { + glBegin(GL_QUADS); + glColor3f(.6, .6, .6); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + + glColor3fv(Color::bgShadow); + glVertex2f(2, 0); + glVertex2f(15, 0); + glVertex2f(15, 13); + glVertex2f(2, 13); + + glColor3fv(Color::bg); + glVertex2f(2, 2); + glVertex2f(13, 2); + glVertex2f(13, 13); + glVertex2f(2, 13); + glEnd(); +} + +void TransparentButton::Draw(void) { + glColor3f(1, 1, 1); + glBegin(GL_LINE_LOOP); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex2f(1, 1); + glVertex2f(14, 1); + glVertex2f(14, 14); + glVertex2f(1, 14); + glEnd(); +} + +} + diff --git a/src/gui_button.h b/src/gui_button.h new file mode 100644 index 0000000..d8b3031 --- /dev/null +++ b/src/gui_button.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include "gui_widget.h" + +namespace Gui { + class Button: public Widget { + public: + Button(void); + virtual ~Button(void) {} + virtual void OnMouseDown(MouseButtonEvent* e); + virtual void OnMouseUp(MouseButtonEvent* e); + virtual void OnActivate(void); + + /* + * onClick only happens when press and release are both on widget, + * (release can be elsewhere). + */ + sigc::signal onPress; + sigc::signal onRelease; + sigc::signal onClick; + bool IsPressed(void) { return m_isPressed; } + private: + void OnRawMouseUp(SDL_MouseButtonEvent* e); + void OnRawKeyUp(SDL_KeyboardEvent* e); + + bool m_isPressed; + sigc::connection _m_release; + sigc::connection _m_kbrelease; + }; + + class SolidButton: public Button { + public: + SolidButton(void) : Button() {} + virtual ~SolidButton(void) {} + virtual void GetSizeRequested(float size[2]); + virtual void Draw(void); + }; + + class TransparentButton : public Button { + public: + TransparentButton(void) : Button() {} + virtual ~TransparentButton(void) {} + virtual void GetSizeRequested(float size[2]); + virtual void Draw(void); + }; +} + diff --git a/src/gui_container.cpp b/src/gui_container.cpp new file mode 100644 index 0000000..a897783 --- /dev/null +++ b/src/gui_container.cpp @@ -0,0 +1,92 @@ +#include "gui.h" +#include "gui_container.h" + +namespace Gui { + +void Container::HandleMouseEvent(MouseButtonEvent* e) { + float x = e->x; + float y = e->y; + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + float pos[2], size[2]; + if(!(*i).w->IsVisible()) continue; + int evmask = (*i).w->GetEventMask(); + if(e->isdown) { + if(!(evmask & Widget::EVENT_MOUSEDOWN)) continue; + } else { + if(!(evmask & Widget::EVENT_MOUSEUP)) continue; + } + (*i).w->GetPosition(pos); + (*i).w->GetSize(size); + + if((x >= pos[0]) && (x < pos[0]+size[0]) && + (y >= pos[1]) && (y < pos[1]+size[1])) { + e->x = x-pos[0]; + e->y = y-pos[1]; + if(e->isdown) { + (*i).w->OnMouseDown(e); + } else { + (*i).w->OnMouseUp(e); + } + } + } +} + +void Container::DeleteAllChildren(void) { + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + delete (*i).w; + } + m_children.clear(); +} + +void Container::PrependChild(Widget* child, float x, float y) { + widget_pos wp; + wp.w = child; + wp.pos[0] = x; wp.pos[1] = y; + child->SetPosition(x, y); + child->SetParent(this); + m_children.push_front(wp); +} + +void Container::AppendChild(Widget* child, float x, float y) { + widget_pos wp; + wp.w = child; + wp.pos[0] = x; wp.pos[1] = y; + child->SetPosition(x, y); + child->SetParent(this); + m_children.push_back(wp); +} + +void Container::Draw(void) { + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + if(!(*i).w->IsVisible()) continue; + glPushMatrix(); + glTranslatef((*i).pos[0], (*i).pos[1], 0); + (*i).w->Draw(); + glPopMatrix(); + } +} + +void Container::OnMouseDown(MouseButtonEvent* e) { + HandleMouseEvent(e); +} + +void Container::OnMouseUp(MouseButtonEvent* e) { + HandleMouseEvent(e); +} + +void Container::ShowAll(void) { + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + (*i).w->Show(); + } + Show(); +} + +void Container::HideAll(void) { + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + (*i).w->Hide(); + } + Hide(); +} + +} + diff --git a/src/gui_container.h b/src/gui_container.h new file mode 100644 index 0000000..50e6734 --- /dev/null +++ b/src/gui_container.h @@ -0,0 +1,29 @@ +#pragma once +/* Parent of all widgets that contain other widgets. */ + +#include +#include "gui_widget.h" + +namespace Gui { + class Container : public Widget { + public: + void OnMouseDown(MouseButtonEvent* e); + void OnMouseUp(MouseButtonEvent* e); + void DeleteAllChildren(void); + virtual void Draw(void); + virtual void ShowAll(void); + virtual void HideAll(void); + private: + void HandleMouseEvent(MouseButtonEvent* e); + protected: + void PrependChild(Widget* w, float x, float y); + void AppendChild(Widget* w, float x, float y); + + struct widget_pos { + Widget* w; + float pos[2]; + }; + std::list m_children; + }; +} + diff --git a/src/gui_events.h b/src/gui_events.h new file mode 100644 index 0000000..2ab060c --- /dev/null +++ b/src/gui_events.h @@ -0,0 +1,9 @@ +#pragma once +namespace Gui { + struct MouseButtonEvent { + Uint8 isdown; + Uint8 button; + float x, y; + }; +} + diff --git a/src/gui_fixed.cpp b/src/gui_fixed.cpp new file mode 100644 index 0000000..a58706e --- /dev/null +++ b/src/gui_fixed.cpp @@ -0,0 +1,62 @@ +#include "libs.h" +#include "gui.h" +#include "l3d.h" + +namespace Gui { + +Fixed::Fixed(float x, float y, float w, float h) { + SetPosition(x, y); + SetSize(w, h); + memcpy(m_bgcol, Color::bg, 3*sizeof(float)); + m_w = w; m_h = h; + m_transparent = false; + m_eventMask = EVENT_ALL; + Screen::AddBaseWidget(this); +} + +void Fixed::GetSizeRequested(float size[2]) { + GetSize(size); +} + +Fixed::~Fixed(void) { + Screen::RemoveBaseWidget(this); +} + +void Fixed::Draw(void) { + if(!m_transparent) { + glBegin(GL_QUADS); + glColor3f(m_bgcol[0], m_bgcol[1], m_bgcol[2]); + glVertex2f(m_w, 0); + glVertex2f(m_w, m_h); + glVertex2f(0, m_h); + glVertex2f(0, 0); + glEnd(); + } + Container::Draw(); +} + +void Fixed::Add(Widget* child, float x, float y) { + AppendChild(child, x, y); +} + +void Fixed::Remove(Widget* child) { + for(std::list::iterator i = m_children.begin(); i != m_children.end(); ++i) { + if((*i).w == child) { + m_children.erase(i); + return; + } + } +} + +void Fixed::SetBgColor(float rgb[3]) { + SetBgColor(rgb[0], rgb[1], rgb[2]); +} + +void Fixed::SetBgColor(float r, float g, float b) { + m_bgcol[0] = r; + m_bgcol[1] = g; + m_bgcol[2] = b; +} + +} + diff --git a/src/gui_fixed.h b/src/gui_fixed.h new file mode 100644 index 0000000..8544ece --- /dev/null +++ b/src/gui_fixed.h @@ -0,0 +1,25 @@ +#pragma once +#include "gui_widget.h" +#include "gui_container.h" + +/* Fixed position widget container. */ + +namespace Gui { + class Fixed : public Container { + public: + Fixed(float x, float y, float w, float h); + void Add(Widget* child, float x, float y); + void Remove(Widget* child); + virtual void Draw(void); + virtual ~Fixed(void); + virtual void GetSizeRequested(float size[2]); + void SetBgColor(float rgb[3]); + void SetBgColor(float r, float g, float b); + void SetTransparency(bool a) { m_transparent = a; } + private: + float m_w, m_h; + float m_bgcol[3]; + bool m_transparent; + }; +} + diff --git a/src/gui_image.cpp b/src/gui_image.cpp new file mode 100644 index 0000000..9be92cd --- /dev/null +++ b/src/gui_image.cpp @@ -0,0 +1,103 @@ +#include "libs.h" +#include "gui_image.h" +#include "l3d.h" + +namespace Gui { + +Image::~Image(void) { +#pragma message("Warning: Leaking GL textures..") +} + +Image::Image(const char* filename) : Widget() { + SDL_Surface* is = IMG_Load(filename); + if(!is) { + fprintf(stderr, "Could not load %s\n", filename); + L3D::Quit(); + } + m_imgw = is->w; + m_imgh = is->h; + + SetSize(m_imgw, m_imgh); + + /* GL textures must be POT, dim > 64. */ + int texw, texh; + { + int nbit = 0; + int sz = m_imgw; + while(sz) { sz >>= 1; nbit++; } + texw = MAX(64, 1<>= 1; nbit++; } + texh = MAX(64, 1<pixels); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glDisable(GL_TEXTURE_2D); + + SDL_FreeSurface(s); +} + +void Image::GetSizeRequested(float size[2]) { + size[0] = m_imgw; + size[1] = m_imgh; +} + +void Image::Draw(void) { + float allocSize[2]; + GetSize(allocSize); + + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_tex); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBegin(GL_QUADS); + float w = m_imgw * m_invtexw; + float h = m_imgh * m_invtexh; + glTexCoord2f(0, h); + glVertex2f(0, 0); + glTexCoord2f(w, h); + glVertex2f(allocSize[0],0); + glTexCoord2f(w, 0); + glVertex2f(allocSize[0], allocSize[1]); + glTexCoord2f(0, 0); + glVertex2f(0, allocSize[1]); + glEnd(); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); +} + +} + diff --git a/src/gui_image.h b/src/gui_image.h new file mode 100644 index 0000000..cee0b3f --- /dev/null +++ b/src/gui_image.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include "gui_widget.h" + +namespace Gui { + class Image : public Widget { + public: + Image(const char* filename); + virtual void Draw(void); + virtual ~Image(void); + virtual void GetSizeRequested(float size[2]); + private: + GLuint m_tex; + int m_imgw, m_imgh; + float m_invtexw, m_invtexh; + }; +} + diff --git a/src/gui_image_button.cpp b/src/gui_image_button.cpp new file mode 100644 index 0000000..652d0e5 --- /dev/null +++ b/src/gui_image_button.cpp @@ -0,0 +1,43 @@ +#include "libs.h" +#include "gui.h" +#include "gui_image_button.h" +#include "l3d.h" + +namespace Gui { + +ImageButton::ImageButton(const char* img_normal) : Button() { + LoadImages(img_normal, NULL); +} + +ImageButton::ImageButton(const char* img_normal, const char* img_pressed) : Button() { + LoadImages(img_normal, img_pressed); +} + +void ImageButton::LoadImages(const char* img_normal, const char* img_pressed) { + m_imgNormal = new Image(img_normal); + float size[2]; + m_imgNormal->GetSizeRequested(size); + SetSize(size[0], size[1]); + + if(img_pressed) m_imgPressed = new Image(img_pressed); + else m_imgPressed = NULL; +} + +void ImageButton::GetSizeRequested(float size[2]) { + m_imgNormal->GetSizeRequested(size); +} + +void ImageButton::Draw(void) { + float size[2]; + GetSize(size); + Gui::Image* img; + if(m_imgPressed && IsPressed()) + img = m_imgPressed; + else + img = m_imgNormal; + img->SetSize(size[0], size[1]); + img->Draw(); +} + +} + diff --git a/src/gui_image_button.h b/src/gui_image_button.h new file mode 100644 index 0000000..39ceded --- /dev/null +++ b/src/gui_image_button.h @@ -0,0 +1,21 @@ +#pragma once +#include + +#include "gui_widget.h" +#include "gui_button.h" + +namespace Gui { + class ImageButton : public Button { + public: + ImageButton(const char* img_normal); + ImageButton(const char* img_normal, const char* img_pressed); + virtual void Draw(void); + virtual ~ImageButton(void) {} + virtual void GetSizeRequested(float size[2]); + private: + void LoadImages(const char* img_normal, const char* img_pressed); + Image* m_imgNormal; + Image* m_imgPressed; + }; +} + diff --git a/src/gui_image_radio_button.cpp b/src/gui_image_radio_button.cpp new file mode 100644 index 0000000..83c5387 --- /dev/null +++ b/src/gui_image_radio_button.cpp @@ -0,0 +1,30 @@ +#include "libs.h" +#include "gui.h" +#include "gui_image_radio_button.h" +#include "l3d.h" + +namespace Gui { + +ImageRadioButton::ImageRadioButton(RadioGroup* g, const char* img_normal, + const char* img_pressed) : RadioButton(g) { + m_imgNormal = new Image(img_normal); + m_imgPressed = new Image(img_pressed); + float size[2]; + m_imgNormal->GetSizeRequested(size); + SetSize(size[0], size[1]); +} + +void ImageRadioButton::GetSizeRequested(float size[2]) { + m_imgNormal->GetSizeRequested(size); +} + +void ImageRadioButton::Draw(void) { + if(m_pressed) { + m_imgPressed->Draw(); + } else { + m_imgNormal->Draw(); + } +} + +} + diff --git a/src/gui_image_radio_button.h b/src/gui_image_radio_button.h new file mode 100644 index 0000000..b4f4dc7 --- /dev/null +++ b/src/gui_image_radio_button.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include "gui_radio_button.h" + +class RadioButton; + +namespace Gui { + class ImageRadioButton : public RadioButton { + public: + ImageRadioButton(RadioGroup*, const char* img_normal, const char* img_pressed); + virtual void Draw(void); + virtual void GetSizeRequested(float size[2]); + private: + Image* m_imgNormal; + Image* m_imgPressed; + }; +} + diff --git a/src/gui_iselectable.h b/src/gui_iselectable.h new file mode 100644 index 0000000..1a12b71 --- /dev/null +++ b/src/gui_iselectable.h @@ -0,0 +1,10 @@ +#pragma once + +namespace Gui { + class ISelectable { + public: + sigc::signal onSelect; + virtual void SetSelected(bool) = 0; + }; +} + diff --git a/src/gui_label.cpp b/src/gui_label.cpp new file mode 100644 index 0000000..6f59633 --- /dev/null +++ b/src/gui_label.cpp @@ -0,0 +1,41 @@ +#include "gui.h" + +namespace Gui { + +Label::Label(const char* text) { + SetText(text); + m_color[0] = m_color[1] = m_color[2] = 1.0f; +} + +Label::Label(std::string& text) { + SetText(text); + m_color[0] = m_color[1] = m_color[2] = 1.0f; +} + +void Label::SetText(const char* text) { + m_text = text; +} + +void Label::SetText(std::string& text) { + m_text = text; +} + +void Label::Draw(void) { + glColor3fv(m_color); + Screen::RenderString(m_text); +} + +void Label::GetSizeRequested(float size[2]) { +#pragma message("Not setting size correctly.") + size[0] = 70; + size[1] = 10; +} + +void Label::SetColor(float r, float g, float b) { + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; +} + +} + diff --git a/src/gui_label.h b/src/gui_label.h new file mode 100644 index 0000000..5717e37 --- /dev/null +++ b/src/gui_label.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "gui_widget.h" + +namespace Gui { + class Label : public Widget { + public: + Label(const char* text); + Label(std::string& text); + virtual void Draw(void); + virtual ~Label(void) {} + virtual void GetSizeRequested(float size[2]); + void SetText(const char* text); + void SetText(std::string& text); + void SetColor(float r, float g, float b); + private: + std::string m_text; + float m_color[3]; + }; +} + diff --git a/src/gui_multi_state_image_button.cpp b/src/gui_multi_state_image_button.cpp new file mode 100644 index 0000000..8416cb3 --- /dev/null +++ b/src/gui_multi_state_image_button.cpp @@ -0,0 +1,62 @@ +#include "libs.h" +#include "gui.h" + +namespace Gui { + +MultiStateImageButton::MultiStateImageButton(void) : Button() { + m_curState = 0; + m_isSelected = true; + Button::onClick.connect(sigc::mem_fun(this, &MultiStateImageButton::OnActivate)); +} + +MultiStateImageButton::~MultiStateImageButton(void) { + for(std::vector::iterator i = m_states.begin(); i != m_states.end(); ++i) { + delete (*i).image; + } +} + +void MultiStateImageButton::StateNext(void) { + m_curState++; + if(m_curState >= (signed)m_states.size()) m_curState = 0; +} + +void MultiStateImageButton::StatePrev(void) { + m_curState--; + if(m_curState < 0) m_curState = (signed)m_states.size()-1; +} + +void MultiStateImageButton::OnActivate(void) { + /* Only iterate through states once widget is selected. */ + if(m_isSelected) StateNext(); + else { + m_isSelected = true; + onSelect.emit(this); + } + onClick.emit(this); +} + +void MultiStateImageButton::SetSelected(bool state) { + m_isSelected = state; +} + +void MultiStateImageButton::GetSizeRequested(float size[2]) { + assert(m_states.size()); + m_states[0].image->GetSizeRequested(size); +} + +void MultiStateImageButton::Draw(void) { + m_states[m_curState].image->Draw(); +} + +void MultiStateImageButton::AddState(int state, const char* filename) { + State s; + s.state = state; + s.image = new Image(filename); + m_states.push_back(s); + float size[2]; + s.image->GetSizeRequested(size); + SetSize(size[0], size[1]); +} + +} + diff --git a/src/gui_multi_state_image_button.h b/src/gui_multi_state_image_button.h new file mode 100644 index 0000000..4f69a88 --- /dev/null +++ b/src/gui_multi_state_image_button.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include "gui_button.h" +#include "gui_iselectable.h" + +namespace Gui { + class MultiStateImageButton : public Button, public ISelectable { + public: + MultiStateImageButton(void); + virtual void Draw(void); + virtual ~MultiStateImageButton(void); + virtual void GetSizeRequested(float size[2]); + void AddState(int state, const char* filename); + int GetState(void) { return m_states[m_curState].state; } + void StateNext(void); + void StatePrev(void); + virtual void OnActivate(void); + sigc::signal onClick; + virtual void SetSelected(bool state); + private: + struct State { + int state; + Image* image; + }; + std::vector m_states; + int m_curState; + bool m_isSelected; + }; +} + diff --git a/src/gui_radio_button.cpp b/src/gui_radio_button.cpp new file mode 100644 index 0000000..f80852c --- /dev/null +++ b/src/gui_radio_button.cpp @@ -0,0 +1,78 @@ +#include "libs.h" +#include "gui.h" + +#define BUTTON_SIZE 16 + +namespace Gui { + +RadioButton::RadioButton(Gui::RadioGroup* g) { + m_pressed = false; + SetSize(BUTTON_SIZE, BUTTON_SIZE); + g->Add(this); +} + +RadioButton::~RadioButton(void) { + +} + +void RadioButton::OnMouseDown(MouseButtonEvent* e) { + onPress.emit(); + OnActivate(); +} + +void RadioButton::OnActivate(void) { + if(!m_pressed) onSelect.emit(this); + m_pressed = true; +} + +void RadioButton::GetSizeRequested(float& w, float& h) { + w = BUTTON_SIZE; + h = BUTTON_SIZE; +} + +void RadioButton::Draw(void) { + if(m_pressed) { + glBegin(GL_QUADS); + glColor3fv(Color::bgShadow); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + + glColor3f(.6, .6, .6); + glVertex2f(2, 0); + glVertex2f(15, 0); + glVertex2f(15, 13); + glVertex2f(2, 13); + + glColor3fv(Color::bg); + glVertex2f(2, 2); + glVertex2f(13, 2); + glVertex2f(13, 13); + glVertex2f(2, 13); + glEnd(); + } else { + glBegin(GL_QUADS); + glColor3f(.6, .6, .6); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + + glColor3fv(Color::bgShadow); + glVertex2f(2, 0); + glVertex2f(15, 0); + glVertex2f(15, 13); + glVertex2f(2, 13); + + glColor3fv(Color::bg); + glVertex2f(2, 2); + glVertex2f(13, 2); + glVertex2f(13, 13); + glVertex2f(2, 13); + glEnd(); + } +} + +} + diff --git a/src/gui_radio_button.h b/src/gui_radio_button.h new file mode 100644 index 0000000..5febb17 --- /dev/null +++ b/src/gui_radio_button.h @@ -0,0 +1,27 @@ +#ifndef _GUIRADIOBUTTON_H +#define _GUIRADIOBUTTON_H + +#include "gui_widget.h" +#include "gui_iselectable.h" +#include + +namespace Gui { + class RadioGroup; + + class RadioButton: public Button, public ISelectable { + public: + RadioButton(RadioGroup *); + virtual ~RadioButton(); + virtual void Draw(); + virtual void GetSizeRequested(float &w, float &h); + virtual void OnMouseDown(MouseButtonEvent *e); + virtual void OnActivate(); + virtual void SetSelected(bool state) { m_pressed = state; } + bool GetSelected() { return m_pressed; } + protected: + int m_pressed; + }; + +} + +#endif /* _GUIRADIOBUTTON_H */ diff --git a/src/gui_radio_group.cpp b/src/gui_radio_group.cpp new file mode 100644 index 0000000..cefef86 --- /dev/null +++ b/src/gui_radio_group.cpp @@ -0,0 +1,21 @@ +#include "libs.h" +#include "gui_radio_group.h" +#include "gui_iselectable.h" + +namespace Gui { + +void RadioGroup::Add(ISelectable* b) { + b->onSelect.connect(sigc::mem_fun(*this, &RadioGroup::OnSelected)); + m_members.push_back(b); +} + +void RadioGroup::OnSelected(ISelectable* b) { + for(std::list::iterator i = m_members.begin(); i != m_members.end(); ++i) { + if(*i != b) { + (*i)->SetSelected(false); + } + } +} + +} + diff --git a/src/gui_radio_group.h b/src/gui_radio_group.h new file mode 100644 index 0000000..b2a4ccf --- /dev/null +++ b/src/gui_radio_group.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include "gui.h" + +namespace Gui { + class RadioGroup { + public: + RadioGroup(void) {}; + virtual ~RadioGroup(void) {}; + void Add(ISelectable* b); + private: + void OnSelected(ISelectable* b); + std::list m_members; + }; +} + diff --git a/src/gui_screen.cpp b/src/gui_screen.cpp new file mode 100644 index 0000000..693c09a --- /dev/null +++ b/src/gui_screen.cpp @@ -0,0 +1,195 @@ +#include "gui.h" +#include "glfreetype.h" + +namespace Gui { + +FontFace* Screen::font; +bool Screen::init = false; +int Screen::width; +int Screen::height; +int Screen::realWidth; +int Screen::realHeight; +float Screen::invRealWidth; +float Screen::invRealHeight; +std::list Screen::widgets; +std::list Screen::kbshortcut_widgets; +float Screen::font_xsize; +float Screen::font_ysize; +std::vector Screen::labelPositions; + +void Screen::Init(int real_width, int real_height, int ui_width, int ui_height) { + Screen::width = ui_width; + Screen::height = ui_height; + Screen::realWidth = real_width; + Screen::realHeight = real_height; + Screen::invRealWidth = 1.0f/real_width; + Screen::invRealHeight = 1.0f/real_height; + Screen::init = true; + Screen::font = new FontFace("font.ttf"); + Screen::font_xsize = 16*0.8; + Screen::font_ysize = 16; +} + +GLint Screen::Project(GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble* model, + const GLdouble* proj, const GLint* view, + GLdouble* winX, GLdouble* winY, GLdouble* winZ) { + + GLint o = gluProject(objX, objY, objZ, model, proj, view, winX, winY, winZ); + *winX = (*winX) * width * invRealWidth; + *winY = (*winY) * height * invRealHeight; + return o; +} + +void Screen::EnterOrtho(void) { + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + //glOrtho(9, 320, 0, 200, -1, 1); + glOrtho(0, width, 0, height, -1, 1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); +} + +void Screen::LeaveOrtho(void) { + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + +void Screen::Draw(void) { + assert(Screen::init); + labelPositions.clear(); + EnterOrtho(); + + for(std::list::iterator i = Screen::widgets.begin(); i != Screen::widgets.end(); ++i) { + if(!(*i)->IsVisible()) continue; + glPushMatrix(); + float pos[2]; + (*i)->GetPosition(pos); + glTranslatef(pos[0], pos[1], 0); + (*i)->Draw(); + glPopMatrix(); + } + LeaveOrtho(); +} + +void Screen::AddBaseWidget(Widget* w) { + Screen::widgets.push_back(w); +} + +void Screen::RemoveBaseWidget(Widget* w) { + Screen::widgets.remove(w); +} + +void Screen::OnClick(SDL_MouseButtonEvent* e) { + MouseButtonEvent ev; + float x = e->x; + float y = e->y; + y = height-(y*height*invRealHeight); + x = x*width*invRealWidth; + ev.button = e->button; + ev.isdown = (e->type == SDL_MOUSEBUTTONDOWN); + ev.x = x; + ev.y = y; + OnClickTestLabels(ev); + for(std::list::iterator i = Screen::widgets.begin(); i != Screen::widgets.end(); ++i) { + float size[2], pos[2]; + if(!(*i)->IsVisible()) continue; + int evmask = (*i)->GetEventMask(); + if(ev.isdown) { + if(!(evmask & Widget::EVENT_MOUSEDOWN)) continue; + } else { + if(!(evmask & Widget::EVENT_MOUSEUP)) continue; + } + (*i)->GetPosition(pos); + (*i)->GetSize(size); + + if((x >= pos[0]) && (x < pos[0]+size[0]) && + (y >= pos[1]) && (y < pos[1]+size[1])) { + + ev.x = x-pos[0]; + ev.y = y-pos[1]; + + if(ev.isdown) { + (*i)->OnMouseDown(&ev); + } else { + (*i)->OnMouseUp(&ev); + } + } + } +} + +void Screen::OnClickTestLabels(const Gui::MouseButtonEvent& ev) { + /* Hm, shame the UI is fixed size for this purpose.. */ + for(std::vector::iterator l = labelPositions.begin(); l != labelPositions.end(); ++l) { + float dx = abs((*l).x - ev.x); + float dy = abs((*l).y - ev.y); + + if((dx < 5) && (dy < 5)) { + (*l).onClick.emit(&ev); + } + } +} + +void Screen::OnKeyDown(const SDL_keysym* sym) { + for(std::list::iterator i = kbshortcut_widgets.begin(); i != kbshortcut_widgets.end(); ++i) { + if(!(*i)->IsVisible()) continue; + (*i)->OnPreShortcut(sym); + } +} + +void Screen::RenderString(const std::string& s) { + glPushMatrix(); + glScalef(Screen::font_xsize, Screen::font_ysize, 1); + font->RenderString(s.c_str()); + glPopMatrix(); +} + +bool Screen::CanPutLabel(float x, float y) { + for(std::vector::iterator i = labelPositions.begin(); i != labelPositions.end(); ++i) { + if((fabs(x-(*i).x) < 5) && + (fabs(y-(*i).y) < 5)) return false; + } + return true; +} + +void Screen::RenderLabel(const std::string& s, float x, float y) { + if(CanPutLabel(x, y)) { + labelPositions.push_back(LabelPos(x, y)); + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(Screen::font_xsize, Screen::font_ysize, 1); + glTranslatef(0.5*font->GetWidth(), -0.4*font->GetHeight(), 0); + font->RenderString(s.c_str()); + glPopMatrix(); + } +} + +void Screen::PutClickableLabel(const std::string& s, float x, float y, + sigc::slot slot) { + + if(CanPutLabel(x, y)) { + LabelPos p = LabelPos(x, y); + p.onClick.connect(slot); + labelPositions.push_back(p); + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(Screen::font_xsize, Screen::font_ysize, 1); + glTranslatef(0.5*font->GetWidth(), -0.4*font->GetHeight(), 0); + font->RenderString(s.c_str()); + glPopMatrix(); + } +} + +void Screen::AddShortcutWidget(Widget* w) { + kbshortcut_widgets.push_back(w); +} + +} + diff --git a/src/gui_screen.h b/src/gui_screen.h new file mode 100644 index 0000000..ab72bcb --- /dev/null +++ b/src/gui_screen.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include "gui.h" + +class FontFace; + +namespace Gui { + class Screen { + public: + static void Init(int real_width, int real_height, int ui_width, int ui_height); + static void Draw(void); + static void AddBaseWidget(Widget* w); + static void RemoveBaseWidget(Widget* w); + static void OnClick(SDL_MouseButtonEvent* e); + static void OnKeyDown(const SDL_keysym* sym); + static void RenderString(const std::string& s); + static void PutClickableLabel(const std::string& s, float x, float y, + sigc::slot slot); + static void RenderLabel(const std::string& s, float x, float y); + static void EnterOrtho(void); + static void LeaveOrtho(void); + static int GetWidth(void) { return width; } + static int GetHeight(void) { return height; } + /* gluProject but fixes UI/screen size mismatch. */ + static GLint Project(GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble* model, + const GLdouble* proj, const GLint* view, GLdouble* winX, + GLdouble* winY, GLdouble* winZ); + friend void Widget::SetShortcut(SDLKey key, SDLMod mod); + private: + struct LabelPos { + LabelPos(float _x, float _y) : x(_x), y(_y) {} + float x, y; + sigc::signal onClick; + }; + static std::vector labelPositions; + static void OnClickTestLabels(const Gui::MouseButtonEvent& ev); + static bool CanPutLabel(float x, float y); + static void AddShortcutWidget(Widget* w); + + static bool init; + static int width, height; + static int realWidth, realHeight; + static float invRealWidth, invRealHeight; + static std::list widgets; + static std::list kbshortcut_widgets; + static FontFace* font; + static float font_xsize; + static float font_ysize; + }; +} + diff --git a/src/gui_toggle_button.cpp b/src/gui_toggle_button.cpp new file mode 100644 index 0000000..7321469 --- /dev/null +++ b/src/gui_toggle_button.cpp @@ -0,0 +1,75 @@ +#include "libs.h" +#include "gui.h" + +#define BUTTON_SIZE 16 + +namespace Gui { + +ToggleButton::ToggleButton(void) { + m_pressed = false; + SetSize(BUTTON_SIZE, BUTTON_SIZE); +} + +void ToggleButton::OnMouseDown(MouseButtonEvent* e) { + if(e->button == 1) { + onPress.emit(); + m_pressed = !m_pressed; + if(m_pressed) { + onSelect.emit(this); + } else { + onDeselect.emit(this); + } + } +} + +void ToggleButton::GetSizeRequested(float& w, float& h) { + w = BUTTON_SIZE; + h = BUTTON_SIZE; +} + +void ToggleButton::Draw(void) { + if(m_pressed) { + glBegin(GL_QUADS); + glColor3fv(Color::bgShadow); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + + glColor3f(.6, .6, .6); + glVertex2f(2, 0); + glVertex2f(15, 0); + glVertex2f(15, 13); + glVertex2f(2, 13); + + glColor3fv(Color::bg); + glVertex2f(2, 2); + glVertex2f(13, 2); + glVertex2f(13, 13); + glVertex2f(2, 13); + glEnd(); + } else { + glBegin(GL_QUADS); + glColor3f(.6, .6, .6); + glVertex2f(0, 0); + glVertex2f(15, 0); + glVertex2f(15, 15); + glVertex2f(0, 15); + + glColor3fv(Color::bgShadow); + glVertex2f(2, 0); + glVertex2f(15, 0); + glVertex2f(15, 13); + glVertex2f(2, 13); + + glColor3fv(Color::bg); + glVertex2f(2, 2); + glVertex2f(13, 2); + glVertex2f(13, 13); + glVertex2f(2, 13); + glEnd(); + } +} + +} + diff --git a/src/gui_toggle_button.h b/src/gui_toggle_button.h new file mode 100644 index 0000000..7020130 --- /dev/null +++ b/src/gui_toggle_button.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include "gui_widget.h" + +namespace Gui { + class ToggleButton : public Button { + public: + ToggleButton(void); + virtual void Draw(void); + virtual ~ToggleButton(void) {} + virtual void GetSizeRequested(float& w, float& h); + virtual void OnMouseDown(MouseButtonEvent* e); + void SetPressed(bool s) { m_pressed = s; } + bool GetPressed(void) { return m_pressed; } + + sigc::signal onSelect; + sigc::signal onDeselect; + private: + int m_pressed; + }; +} + diff --git a/src/gui_widget.cpp b/src/gui_widget.cpp new file mode 100644 index 0000000..7699acc --- /dev/null +++ b/src/gui_widget.cpp @@ -0,0 +1,24 @@ +#include "gui.h" + +namespace Gui { + +Widget::Widget(void) { + m_visible = false; + m_eventMask = EVENT_NONE; +} + +void Widget::SetShortcut(SDLKey key, SDLMod mod) { + m_shortcut.sym = key; + m_shortcut.mod = mod; + Screen::AddShortcutWidget(this); +} + +void Widget::OnPreShortcut(const SDL_keysym* sym) { + int mod = sym->mod & 0xfff; /* Filters out numlock, capslock, which screws things up.. */ + if((sym->sym == m_shortcut.sym) && (mod == m_shortcut.mod)) { + OnActivate(); + } +} + +} + diff --git a/src/gui_widget.h b/src/gui_widget.h new file mode 100644 index 0000000..71448fa --- /dev/null +++ b/src/gui_widget.h @@ -0,0 +1,51 @@ +#pragma once +#include "gui_events.h" + +namespace Gui { + class Container; + class Widget { + public: + Widget(void); + virtual void Draw(void) = 0; + virtual ~Widget(void) {} + virtual void GetSizeRequested(float size[2]) = 0; + void GetPosition(float pos[2]) { pos[0] = m_size.x; pos[1] = m_size.y; } + void SetPosition(float x, float y) { m_size.x = x; m_size.y = y; } + void GetSize(float size[2]) { size[0] = m_size.w; size[1] = m_size.h; } + void SetSize(float w, float h) { m_size.w = w; m_size.h = h; }; + void SetShortcut(SDLKey key, SDLMod mod); + virtual void Show(void) { m_visible = true; } + virtual void Hide(void) { m_visible = false; } + bool IsVisible(void) { return m_visible; } + Container* GetParent(void) { return m_parent; } + void SetParent(Container* p) { m_parent = p; } + + virtual void OnMouseDown(MouseButtonEvent* e) {} + virtual void OnMouseUp(MouseButtonEvent* e) {} + virtual void OnActivate(void) {} + /* Only to be called by Screen::OnKeyDown. */ + void OnPreShortcut(const SDL_keysym* sym); + enum EventMask { + EVENT_NONE = 0, + EVENT_KEYDOWN = 1<<0, + EVENT_KEYUP = 1<<1, + EVENT_MOUSEDOWN = 1<<2, + EVENT_MOUSEUP = 1<<3, + EVENT_ALL = 0xffffffff + }; + unsigned int GetEventMask(void) { return m_eventMask; } + protected: + unsigned int m_eventMask; + struct { + SDLKey sym; + SDLMod mod; + } m_shortcut; + private: + struct { + float x,y,w,h; + } m_size; + bool m_visible; + Container* m_parent; + }; +} + diff --git a/src/l3d.h b/src/l3d.h new file mode 100644 index 0000000..4b862a5 --- /dev/null +++ b/src/l3d.h @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include "libs.h" +#include "gui.h" +#include "view.h" +#include "mtrand.h" + +class Player; +class SectorView; +class SystemView; +class WorldView; +class SystemInfoView; +class ShipCpanel; +class StarSystem; +class SpaceStationView; + +class IniConfig: private std::map { +public: + IniConfig(const char* filename); + int Int(const char* key) { + return atoi((*this)[key].c_str()); + } + float Float(const char* key) { + float val; + if(sscanf((*this)[key].c_str(), "%f", &val)==1) return val; + else return 0; + } + std::string String(const char* key) { + return (*this)[key]; + } +}; + +/* Implementation is done in main.cpp, just to confuse you. :D */ +class L3D { +public: + static void Init(IniConfig& config); + static void MainLoop(void); + static void Quit(void); + static float GetFrameTime(void) { return frameTime; } + static double GetGameTime(void) { return gameTime; } + static void SetTimeStep(float s) { timeStep = s; } + static float GetTimeStep(void) { return timeStep; } + static int GetScrWidth(void) { return scrWidth; } + static int GetScrHeight(void) { return scrHeight; } + static int GetScrAspect(void) { return scrAspect; } + static int KeyState(SDLKey k) { return keyState[k]; } + static int MouseButtonState(int button) { return mouseButton[button]; } + static void GetMouseMotion(int motion[2]) { + memcpy(motion, mouseMotion, sizeof(int)*2); + } + + static sigc::signal onKeyPress; + static sigc::signal onKeyRelease; + static sigc::signal onMouseButtonUp; + static sigc::signal onMouseButtonDown; + + static MTRand rng; + + static void HyperspaceTo(StarSystem* destination); + enum CamType { CAM_FRONT, CAM_REAR, CAM_EXTERNAL }; + enum MapView { MAP_NOMAP, MAP_SECTOR, MAP_SYSTEM }; + static void SetCamType(enum CamType); + static void SetMapView(enum MapView); + static enum CamType GetCamType(void) { return cam_type; } + static enum MapView GetMapView(void) { return map_view; } + static void SetView(View* v); + static View* GetView(void) { return current_view; } + static StarSystem* GetSelectedSystem(void); + + static Player* player; + static SectorView* sector_view; + static SystemInfoView* system_info_view; + static WorldView* world_view; + static SpaceStationView* spaceStationView; + + static ShipCpanel* cpan; + +private: + static void InitOpenGL(void); + static void HandleEvents(void); + + static View* current_view; + static SystemView* system_view; + + static double gameTime; + static StarSystem* selected_system; + static enum CamType cam_type; + static enum MapView map_view; + static float timeStep; + static float frameTime; + static int scrWidth, scrHeight; + static float scrAspect; + static SDL_Surface* scrSurface; + static char keyState[SDLK_LAST]; + static char mouseButton[5]; + static int mouseMotion[2]; +}; + diff --git a/src/libs.h b/src/libs.h new file mode 100644 index 0000000..709d695 --- /dev/null +++ b/src/libs.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#define snprintf _snprintf +#define alloca _alloca +#endif + +#include "vector3.h" +#include "matrix4x4.h" +#include "mtrand.h" + +#include "date.h" + +#ifndef dDOUBLE +#error LibODE is not compiled with double-precision floating point. Please get/compile libode with \ + double-precision floating point. +#endif + +#define DEBUG + +/* + * Normal use: + * foreach(container, iter) { do_something(*iter); } + * + * When removing items: + * foreach(container, iter) { + * if(*iter == some_value) { + * iter = container.erase(iter); // Assign not necessary for maps. + * --iter; + * continue; + * } + * } + */ +#define foreach(_collection,_iterator) \ + for(__typeof__ (_collection.end()) _iterator = (collection).begin (); \ + _iterator 1= (_collection).end(); ++(_iterator)); + +#define MIN(x,y) ((x)<(y)?(x):(y)) +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define CLAMP(a, min, max) (((a) > (max)) ? (max) : (((a) < (min)) ? (min) : (a))) + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..f58d745 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,362 @@ +#include "libs.h" +#include "l3d.h" +#include "gui.h" +#include "glfreetype.h" +#include "objimport.h" +#include "player.h" +#include "space.h" +#include "planet.h" +#include "star.h" +#include "frame.h" +#include "ship_cpanel.h" +#include "sector_view.h" +#include "system_view.h" +#include "system_info_view.h" +#include "world_view.h" +#include "star_system.h" +#include "space_station.h" +#include "space_station_view.h" + +float L3D::timeStep = 1.0f; +int L3D::scrWidth; +int L3D::scrHeight; +float L3D::scrAspect; +SDL_Surface* L3D::scrSurface; +sigc::signal L3D::onKeyPress; +sigc::signal L3D::onKeyRelease; +sigc::signal L3D::onMouseButtonUp; +sigc::signal L3D::onMouseButtonDown; +char L3D::keyState[SDLK_LAST]; +char L3D::mouseButton[5]; +int L3D::mouseMotion[2]; +enum L3D::CamType L3D::cam_type; +enum L3D::MapView L3D::map_view; +Player* L3D::player; +View* L3D::current_view; +WorldView* L3D::world_view; +SpaceStationView* L3D::spaceStationView; +SectorView* L3D::sector_view; +SystemView* L3D::system_view; +SystemInfoView* L3D::system_info_view; +ShipCpanel* L3D::cpan; +StarSystem* L3D::selected_system; +MTRand L3D::rng; +double L3D::gameTime; +float L3D::frameTime; + +void L3D::Init(IniConfig& config) { + int width = config.Int("ScrWidth"); + int height = config.Int("ScrHeight"); + const SDL_VideoInfo* info = NULL; + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError()); + exit(-1); + } + + info = SDL_GetVideoInfo(); + + switch(config.Int("ScrDepth")) { + case 16: + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,6); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + break; + case 32: + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + break; + default: + fprintf(stderr, "Fatal error: Invalid screen depth in config.ini.\n"); + L3D::Quit(); + } + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + Uint32 flags = SDL_OPENGL; + if(config.Int("StartFullscreen")) flags |= SDL_FULLSCREEN; + + if((L3D::scrSurface = SDL_SetVideoMode(width, height, info->vfmt->BitsPerPixel, flags)) == 0) { + fprintf(stderr, "Video mode set failed: %s\n", SDL_GetError()); + exit(-1); + } + + L3D::scrWidth = width; + L3D::scrHeight = height; + L3D::scrAspect = width / (float)height; + + InitOpenGL(); + + dInitODE(); + GLFTInit(); + Space::Init(); +} + +void L3D::InitOpenGL() { + glShadeModel(GL_SMOOTH); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glClearColor(0, 0, 0, 0); + glViewport(0, 0, scrWidth, scrHeight); +} + +void L3D::Quit(void) { + SDL_Quit(); + exit(0); +} + +void L3D::SetCamType(enum CamType c) { + cam_type = c; + map_view = MAP_NOMAP; + SetView(world_view); +} + +void L3D::SetMapView(enum MapView v) { + map_view = v; + if(v == MAP_SECTOR) + SetView(sector_view); + else + SetView(system_view); +} + +void L3D::SetView(View* v) { + if(current_view) current_view->HideAll(); + current_view = v; + current_view->ShowAll(); +} + +void L3D::HandleEvents(void) { + SDL_Event event; + + L3D::mouseMotion[0] = L3D::mouseMotion[1] = 0; + while(SDL_PollEvent(&event)) { + Gui::HandleSDLEvent(&event); + switch(event.type) { + case SDL_KEYDOWN: + if(event.key.keysym.sym == SDLK_q) L3D::Quit(); + if(event.key.keysym.sym == SDLK_F11) SDL_WM_ToggleFullScreen(L3D::scrSurface); + + L3D::keyState[event.key.keysym.sym] = 1; + L3D::onKeyPress.emit(&event.key.keysym); + break; + case SDL_KEYUP: + L3D::keyState[event.key.keysym.sym] = 0; + L3D::onKeyRelease.emit(&event.key.keysym); + break; + case SDL_MOUSEBUTTONDOWN: + L3D::mouseButton[event.button.button] = 1; + L3D::onMouseButtonDown.emit(event.button.button, + event.button.x, event.button.y); + break; + case SDL_MOUSEBUTTONUP: + L3D::mouseButton[event.button.button] = 1; + L3D::onMouseButtonUp.emit(event.button.button, + event.button.x, event.button.y); + break; + case SDL_MOUSEMOTION: + SDL_GetRelativeMouseState(&L3D::mouseMotion[0], &L3D::mouseMotion[1]); + break; + case SDL_QUIT: + L3D::Quit(); + break; + } + } +} + +void L3D::MainLoop(void) { + Frame* earth_frame = new Frame(Space::GetRootFrame(), "Earth"); + earth_frame->SetPosition(vector3d(149598000000.0, 0, 0)); + earth_frame->SetRadius(2*380000000); /* 2 moon orbital radii. */ + + player = new Player(); + player->SetLabel("Me"); + player->SetFrame(earth_frame); + player->SetPosition(vector3d(100, 0, 0)); + Space::AddBody(player); + + for(int i = 0; i < 4; i++) { + Ship* body = new Ship(); + char buf[64]; + snprintf(buf, sizeof(buf), "X%c-0%02d", "A"+i, i); + body->SetLabel(buf); + body->SetFrame(earth_frame); + body->SetPosition(vector3d(i*200, 0, -200)); + Space::AddBody(body); + } + + { + SpaceStation* body = new SpaceStation(); + body->SetLabel("Some Back Country Joint"); + body->SetFrame(earth_frame); + body->SetPosition(vector3d(0, 0, 6000)); + Space::AddBody(body); + } + + Planet* planet = new Planet(StarSystem::SBody::SUBTYPE_PLANET_INDIGENOUS_LIFE); + planet->SetLabel("Earth"); + planet->SetPosition(vector3d(0, 0, -8000000.0)); + planet->SetFrame(earth_frame); + Space::AddBody(planet); + + Frame* moon_frame = new Frame(earth_frame, "Moon"); + moon_frame->SetPosition(vector3d(0, -380000000.0, 0)); + moon_frame->SetRadius(10*1738140.0); /* 10 moon radii. */ + Planet* moon = new Planet(StarSystem::SBody::SUBTYPE_PLANET_DWARF); + moon->SetLabel("Moon"); + moon->SetPosition(vector3d(0, 0, 0)); + moon->SetRadius(1738140.0); + moon->SetFrame(moon_frame); + Space::AddBody(moon); + + Star* sol = new Star(StarSystem::SBody::SUBTYPE_STAR_G); + sol->SetLabel("Sol"); + sol->SetRadius(6.955e8); + sol->SetPosition(vector3d(0, 0, 0)); + sol->SetFrame(Space::GetRootFrame()); + Space::AddBody(sol); + + Gui::Init(scrWidth, scrHeight, 640, 480); + + cpan = new ShipCpanel(); + cpan->ShowAll(); + + sector_view = new SectorView(); + system_view = new SystemView(); + system_info_view = new SystemInfoView(); + world_view = new WorldView(); + spaceStationView = new SpaceStationView(); + + SetView(world_view); + + GLUquadric* quad = gluNewQuadric(); + gluQuadricOrientation(quad, GLU_INSIDE); + + Uint32 last_stats = SDL_GetTicks(); + int frame_stat = 0; + char fps_readout[32]; + Uint32 time_before_frame = SDL_GetTicks(); + + for(;;) { + frame_stat++; + glMatrixMode(GL_MODELVIEW); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + current_view->Draw3D(); + /* + * TODO: HandleEvents at the moment must be after view->Draw3D and before + * Gui::Draw so that labels drawn to screen can have mouse events correctly + * detected. Gui::Draw wipes memory of label positions. + */ + L3D::HandleEvents(); + /* Hide cursor for ship control. */ + if(L3D::MouseButtonState(3)) { + SDL_ShowCursor(0); + SDL_WM_GrabInput(SDL_GRAB_ON); + } else { + SDL_ShowCursor(1); + SDL_WM_GrabInput(SDL_GRAB_OFF); + } + + Gui::Draw(); +#ifdef DEBUG + { + Gui::Screen::EnterOrtho(); + glColor3f(1, 1, 1); + glTranslatef(0, Gui::Screen::GetHeight()-20, 0); + Gui::Screen::RenderString(fps_readout); + Gui::Screen::LeaveOrtho(); + } +#endif + + glFlush(); + SDL_GL_SwapBuffers(); + //if(glGetError()) printf("GL: %s\n", gluErrorString(glGetError())); + + L3D::frameTime = 0.001*(SDL_GetTicks() - time_before_frame); + float step = L3D::timeStep * L3D::frameTime; + + time_before_frame = SDL_GetTicks(); + /* Game state update stuff. */ + if(step) { + Space::TimeStep(step); + gameTime += step; + } + current_view->Update(); + + if(SDL_GetTicks() - last_stats > 1000) { + snprintf(fps_readout, sizeof(fps_readout), "%d fps", frame_stat); + frame_stat = 0; + last_stats += 1000; + } + } +} + +StarSystem* L3D::GetSelectedSystem(void) { + int sector_x, sector_y, system_idx; + L3D::sector_view->GetSelectedSystem(§or_x, §or_y, &system_idx); + if(system_idx == -1) { + selected_system = 0; + return NULL; + } + if(selected_system) { + if(!selected_system->IsSystem(sector_x, sector_y, system_idx)) { + delete selected_system; + selected_system = 0; + } + } + if(!selected_system) { + selected_system = new StarSystem(sector_x, sector_y, system_idx); + } + return selected_system; +} + +void L3D::HyperspaceTo(StarSystem* dest) { + Space::Clear(); + Space::BuildSystem(dest); + float ang = rng(M_PI); + L3D::player->SetPosition(vector3d(sin(ang)*8*AU, cos(ang)*8*AU, 0)); +} + +IniConfig::IniConfig(const char* filename) { + FILE* f = fopen(filename, "r"); + if(!f) { + fprintf(stderr, "Could not open '%s'.\n", filename); + L3D::Quit(); + } + char buf[1024]; + while(fgets(buf, sizeof(buf), f)) { + if(buf[0] == '#') continue; + char* sep = strchr(buf, '='); + char* kend = sep; + if(!sep) continue; + *sep = 0; + /* Strip whitespace. */ + while(isspace(*(--kend))) *kend = 0; + while(isspace(*(++sep))) *sep = 0; + /* Snip \r, \n. */ + char* vend = sep; + while(*(++vend)) if((*vend == '\r') || (*vend == '\n')) { *vend = 0; break; } + std::string key = std::string(buf); + std::string val = std::string(sep); + (*this)[key] = val; + } + fclose(f); +} + +int main(int argc, char** argv) { + printf("Lephisto3D's super high tech demo!\n"); + + IniConfig cfg("config.ini"); + + L3D::Init(cfg); + L3D::MainLoop(); + return 0; +} + diff --git a/src/matrix4x4.h b/src/matrix4x4.h new file mode 100644 index 0000000..f9d8775 --- /dev/null +++ b/src/matrix4x4.h @@ -0,0 +1,226 @@ +#pragma once +#include +#include +#include "vector3.h" + +template + +class matrix4x4 { +private: + T cell[16]; +public: + matrix4x4(void) { } + matrix4x4(T val) { + cell[0] = cell[1] = cell[2] = cell[3] = cell[4] = cell[5] = cell[6] = + cell[7] = cell[8] = cell[9] = cell[10] = cell[11] = cell[12] = cell[13] = + cell[14] = cell[15] = val; + } + + /* Row-major 4x3 matrix. */ + void LoadFromOdeMatrix(const T* r) { + cell[ 0] = r[ 0];cell[ 1] = r[ 4]; cell[ 2] = r[ 8];cell[ 3] = 0; + cell[ 4] = r[ 1];cell[ 5] = r[ 5]; cell[ 6] = r[ 9];cell[ 7] = 0; + cell[ 8] = r[ 2];cell[ 9] = r[ 6]; cell[10] = r[10];cell[11] = 0; + cell[12] = 0; cell[13] = 0; cell[14] = 0; cell[15] = 1; + } + + /* Row-major 3x3 matrix. */ + void LoadFrom3x3Matrix(const T* r) { + cell[ 0] = r[ 0]; cell[ 4] = r[ 1]; cell[ 8] = r[ 2]; cell[12] = 0; + cell[ 1] = r[ 3]; cell[ 5] = r[ 4]; cell[ 9] = r[ 5]; cell[13] = 0; + cell[ 2] = r[ 6]; cell[ 6] = r[ 7]; cell[10] = r[ 8]; cell[14] = 0; + cell[ 3] = 0; cell[ 7] = 0; cell[11] = 0; cell[15] = 1; + } + + /* Row-major. */ + void SaveTo3x3Matrix(T* r) { + r[0] = cell[0]; r[1] = cell[4]; r[2] = cell[8]; + r[3] = cell[1]; r[4] = cell[5]; r[5] = cell[9]; + r[6] = cell[2]; r[7] = cell[6]; r[8] = cell[10]; + } + + void SaveToOdeMatrix(T r[12]) { + r[0] = cell[0]; r[1] = cell[4]; r[ 2] = cell[ 8]; r[ 3] = 0; + r[4] = cell[1]; r[5] = cell[5]; r[ 6] = cell[ 9]; r[ 7] = 0; + r[8] = cell[2]; r[9] = cell[6]; r[10] = cell[10]; r[11] = 0; + } + + static matrix4x4 Identity(void) { + matrix4x4 m = matrix4x4(0); + m.cell[0] = m.cell[5] = m.cell[10] = m.cell[15] = 1.0f; + return m; + } + + static matrix4x4 ScaleMatrix(T x, T y, T z) { + matrix4x4 m; + m[ 0] = x; m[ 1] = m[ 2] = m[ 3] = 0; + m[ 5] = y; m[ 4] = m[ 6] = m[ 7] = 0; + m[10] = z; m[ 8] = m[ 9] = m[11] = 0; + m[12] = m[13] = m[14] = 0; m[15] = 1; + return m; + } + + void RotateZ(T radians) { *this = (*this) * RotateZMatrix(radians); } + void RotateY(T radians) { *this = (*this) * RotateYMatrix(radians); } + void rotateX(T radians) { *this = (*this) * RotateXMatrix(radians); } + + static matrix4x4 RotateXMatrix(T radians) { + matrix4x4 m; + T cos_r = cosf(radians); + T sin_r = sinf(radians); + m[ 0] = 1.0f; + m[ 1] = 0; + m[ 2] = 0; + m[ 3] = 0; + + m[ 4] = 0; + m[ 5] = cos_r; + m[ 6] = -sin_r; + m[ 7] = 0; + + m[ 8] = 0; + m[ 9] = sin_r; + m[10] = cos_r; + m[11] = 0; + + m[12] = 0; + m[13] = 0; + m[14] = 0; + m[15] = 1.0f; + return m; + } + + static matrix4x4 RotateYMatrix(T radians) { + matrix4x4 m; + T cos_r = cosf(radians); + T sin_r = sinf(radians); + m[ 0] = cos_r; + m[ 1] = 0; + m[ 2] = sin_r; + m[ 3] = 0; + + m[ 4] = 0; + m[ 5] = 1; + m[ 6] = 0; + m[ 7] = 0; + + m[ 8] = -sin_r; + m[ 9] = 0; + m[10] = cos_r; + m[11] = 0; + + m[12] = 0; + m[13] = 0; + m[14] = 0; + m[15] = 1.0f; + return m; + } + + static matrix4x4 RotateZMatrix(T radians) { + matrix4x4 m; + T cos_r = cosf(radians); + T sin_r = sinf(radians); + m[ 0] = cos_r; + m[ 1] = -sin_r; + m[ 2] = 0; + m[ 3] = 0; + + m[ 4] = sin_r; + m[ 5] = cos_r; + m[ 6] = 0; + m[ 7] = 0; + + m[ 8] = 0; + m[ 9] = 0; + m[10] = 1.9f; + m[11] = 0; + + m[12] = 0; + m[13] = 0; + m[14] = 0; + m[15] = 1.0f; + return m; + } + + T& operator[] (const int i) { return cell[i]; } + friend matrix4x4 operator+(const matrix4x4& a, const matrix4x4& b) { + matrix4x4 m; + for(int i = 0; i < 16; i++) m.cell[i] = a.cell[i] + b.cell[i]; + return m; + } + friend matrix4x4 operator-(const matrix4x4& a, const matrix4x4& b) { + matrix4x4 m; + for(int i = 0; i < 16; i++) m.cell[i] = a.cell[i] - b.cell[i]; + return m; + } + + friend matrix4x4 operator*(const matrix4x4& a, const matrix4x4& b) { + matrix4x4 m; + m.cell[ 0] = a.cell[0]*b.cell[ 0]+a.cell[4]*b.cell[ 1]+a.cell[ 8]*b.cell[ 2]+a.cell[12]*b.cell[ 3]; + m.cell[ 1] = a.cell[1]*b.cell[ 0]+a.cell[5]*b.cell[ 1]+a.cell[ 9]*b.cell[ 2]+a.cell[13]*b.cell[ 3]; + m.cell[ 2] = a.cell[2]*b.cell[ 0]+a.cell[6]*b.cell[ 1]+a.cell[10]*b.cell[ 2]+a.cell[14]*b.cell[ 3]; + m.cell[ 3] = a.cell[3]*b.cell[ 0]+a.cell[7]*b.cell[ 1]+a.cell[11]*b.cell[ 2]+a.cell[15]*b.cell[ 3]; + m.cell[ 4] = a.cell[0]*b.cell[ 4]+a.cell[4]*b.cell[ 5]+a.cell[ 8]*b.cell[ 6]+a.cell[12]*b.cell[ 7]; + m.cell[ 5] = a.cell[1]*b.cell[ 4]+a.cell[5]*b.cell[ 5]+a.cell[ 9]*b.cell[ 6]+a.cell[13]*b.cell[ 7]; + m.cell[ 6] = a.cell[2]*b.cell[ 4]+a.cell[6]*b.cell[ 5]+a.cell[10]*b.cell[ 6]+a.cell[14]*b.cell[ 7]; + m.cell[ 7] = a.cell[3]*b.cell[ 4]+a.cell[7]*b.cell[ 5]+a.cell[11]*b.cell[ 6]+a.cell[15]*b.cell[ 7]; + m.cell[ 8] = a.cell[0]*b.cell[ 8]+a.cell[4]*b.cell[ 9]+a.cell[ 8]*b.cell[10]+a.cell[12]*b.cell[11]; + m.cell[ 9] = a.cell[1]*b.cell[ 8]+a.cell[5]*b.cell[ 9]+a.cell[ 9]*b.cell[10]+a.cell[13]*b.cell[11]; + m.cell[10] = a.cell[2]*b.cell[ 8]+a.cell[6]*b.cell[ 9]+a.cell[10]*b.cell[10]+a.cell[14]*b.cell[11]; + m.cell[11] = a.cell[3]*b.cell[ 8]+a.cell[7]*b.cell[ 9]+a.cell[11]*b.cell[10]+a.cell[15]*b.cell[11]; + m.cell[12] = a.cell[0]*b.cell[12]+a.cell[4]*b.cell[13]+a.cell[ 8]*b.cell[14]+a.cell[12]*b.cell[15]; + m.cell[13] = a.cell[1]*b.cell[12]+a.cell[5]*b.cell[13]+a.cell[ 9]*b.cell[14]+a.cell[13]*b.cell[15]; + m.cell[14] = a.cell[2]*b.cell[12]+a.cell[6]*b.cell[13]+a.cell[10]*b.cell[14]+a.cell[14]*b.cell[15]; + m.cell[15] = a.cell[3]*b.cell[12]+a.cell[7]*b.cell[13]+a.cell[11]*b.cell[14]+a.cell[15]*b.cell[15]; + return m; + } + + friend vector3 operator*(const matrix4x4& a, const vector3 &v) { + vector3 out; + out.x = a.cell[0]*v.x + a.cell[4]*v.y + a.cell[ 8]*v.z + a.cell[12]; + out.y = a.cell[1]*v.x + a.cell[5]*v.y + a.cell[ 9]*v.z + a.cell[13]; + out.z = a.cell[2]*v.x + a.cell[6]*v.y + a.cell[10]*v.z + a.cell[14]; + return out; + } + + vector3 ApplyRotationOnly(const vector3& v) const { + vector3 out; + out.x = cell[0]*v.x + cell[4]*v.y + cell[ 8]*v.z; + out.y = cell[1]*v.x + cell[5]*v.y + cell[ 9]*v.z; + out.z = cell[2]*v.x + cell[6]*v.y + cell[10]*v.z; + return out; + } + + void Translatef(T x, T y, T z) { + matrix4x4 m = Identity(); + m[12] = x; + m[13] = y; + m[14] = z; + *this = (*this) * m; + } + + matrix4x4 InverseOf(void) const { + matrix4x4 m; + /* This only works for matrices containing only rotation and transform. */ + m[ 0] = cell[0]; m[1] = cell[4]; m[ 2] = cell[ 8]; + m[ 4] = cell[1]; m[5] = cell[5]; m[ 6] = cell[ 9]; + m[ 8] = cell[2]; m[9] = cell[6]; m[10] = cell[10]; + m[12] = -(cell[0]*cell[12] + cell[1]*cell[13] + cell[ 2]*cell[14]); + m[13] = -(cell[4]*cell[12] + cell[5]*cell[13] + cell[ 6]*cell[14]); + m[14] = -(cell[8]*cell[12] + cell[9]*cell[13] + cell[10]*cell[14]); + m[ 3] = m[7] = m[11] = 0; + m[15] = 1.0f; + return m; + } + + void Print(void) const { + for(int i = 0; i < 4; i++) { + printf("%.2f %.2f %.2f %.2f\n", cell[i], cell[i+4], cell[i+8], cell[i+12]); + } + printf("\n"); + } +}; + +typedef matrix4x4matrix4x4f; +typedef matrix4x4matrix4x4d; + diff --git a/src/mtrand.cpp b/src/mtrand.cpp new file mode 100644 index 0000000..427d03c --- /dev/null +++ b/src/mtrand.cpp @@ -0,0 +1,53 @@ +#include "mtrand.h" +/* + * Non-inline function definitions and static member definitions cannot + * reside in header file because of the risk of multiple declarations. + */ + +/* Init static private members. */ +//unsigned long MTRand_int32::state[n] = { 0x0UL }; +//int MTRand_int32::p = 0; +//bool MTRand_int32::init = false; + +void MTRand_int32::gen_state(void) { + for(int i = 0; i < (n - m); ++i) + state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]); + for(int i = n - m; i < (n - 1); ++i) + state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]); + state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]); + p = 0; /* Reset position. */ +} + +/* Init by 32 bit seed. */ +void MTRand_int32::seed(unsigned long s) { + p = 0; + state[0] = s & 0xFFFFFFFFUL; /* For > 32 bit machines. */ + for(int i = 1; i < n; ++i) { + state[i] = 181243353UL * (state[i - 1] ^ (state[i - 1] >> 30)) + i; + state[i] &= 0xFFFFFFFFUL; /* For > 32 bit machines. */ + } + p = n; /* Force gen_state() to be called for next random number. */ +} + +/* Init by array. */ +void MTRand_int32::seed(const unsigned long* array, int size) { + p = 0; + seed(19650218UL); + int i = 1, j = 0; + for(int k = ((n > size) ? n : size); k; --k) { + state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL)) + + array[j] + j; /* Non-linear. */ + state[i] &= 0xFFFFFFFFUL; /* For > 32 bit machines. */ + ++j; j %= size; + if((++i) == n) { state[0] = state[n - 1]; i = 1; } + } + + for(int k = n - 1; k; --k) { + state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i; + state[i] &= 0xFFFFFFFFUL; /* For > 32 bit machines. */ + if((++i) == n) { state[0] = state[n - 1]; i = 1; } + } + state[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array. */ + p = n; /* Force gen_state() to be called for next random number. */ +} + diff --git a/src/mtrand.h b/src/mtrand.h new file mode 100644 index 0000000..145aa81 --- /dev/null +++ b/src/mtrand.h @@ -0,0 +1,121 @@ +#pragma once + +/* Mersenne Twister rng. */ +class MTRand_int32 { +public: + /* The default constructor uses default seed only if this is the first instance. */ + MTRand_int32(void) { seed(5489UL); } + /* Constructor with 32 bit int as seed. */ + MTRand_int32(unsigned long s) { seed(s); } + /* Consstructor with array of size 32 bit ints as seed. */ + MTRand_int32(const unsigned long* array, int size) { seed(array, size); } + + void seed(unsigned long); /* Seed with 32 bit integer. */ + void seed(const unsigned long*, int size); /* Seed with array. */ + + /* Overload operator() to make this a generator */ + unsigned long operator()(int min, int max) { + return (rand_int32()%(1+max-min))+min; + } + + virtual ~MTRand_int32(void) { } +protected: /* Used by derived classes, otherwise not accessible; use the ()-operator. */ + unsigned long rand_int32(void); +private: + unsigned long operator()() { return rand_int32(); } + static const int n = 634, m = 397; /* Compile time constants. */ + + /* Static: */ + unsigned long state[n]; /* State vector array. */ + int p; /* Position in array state. */ + + /* Generate the pseudo random numbers. */ + unsigned long twiddle(unsigned long, unsigned long); + void gen_state(void); + + /* Doesn't make much sense having a copy or assignment operator laying around. */ + MTRand_int32(const MTRand_int32&); + void operator=(const MTRand_int32&); +}; + +/* Inline for speed, must therefore reside in header. */ +inline unsigned long MTRand_int32::twiddle(unsigned long u, unsigned long v) { + return (((u & 0x80000000UL) | (v & 0x7FFFFFFFUL)) >> 1) + ^ ((v & 1UL) ? 0x9908B0DFUL : 0x0UL); +} + +/* Generate 32 bit random int. */ +inline unsigned long MTRand_int32::rand_int32(void) { + if(p == n) gen_state(); /* New state vector needed. */ + /* gen_state() is split off to be non-inline, because it is only called once + * in every 624 calls, otherwise irand() would become too big to get inlined. + */ + unsigned long x = state[p++]; + x ^= (x >> 11); + x ^= (x << 8) & 0x9D2C5680UL; + x ^= (x << 15) & 0xEFC60000UL; + return x ^ (x>>18); +} + +/* Generate double floating point numbers in the half-open interval [0, 1] */ +class MTRand : public MTRand_int32 { +public: + MTRand(void) : MTRand_int32() {} + MTRand(unsigned int long seed) : MTRand_int32(seed) {} + MTRand(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand(void) {} + + unsigned long operator()(int min, int max) { + return (rand_int32()%(1+max-min))+min; + } + + double pdrand(int p) { + double o = (*this)(1.0); + while(--p) o *= (*this)(1.0); + return 0; + } + + double operator()(double max) { + /* Divided by 2^32 */ + return max*static_cast(rand_int32()) * (1./4294967296.); + } + +private: + /* Copy and assignment operators not defined. */ + MTRand(const MTRand&); + void operator=(const MTRand&); +}; + +/* Generate double floating point numbers in the closed interval [0, 1]. */ +class MTRand_closed : public MTRand_int32 { +public: + MTRand_closed(void) : MTRand_int32() {} + MTRand_closed(unsigned long seed) : MTRand_int32(seed) {} + MTRand_closed(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + ~MTRand_closed(void) {} + double operator()() { + /* Divided by 2^32 - 1. */ + return static_cast(rand_int32()) * (1./4294967295.); } +private: + /* Copy and assignment operators not defined. */ + MTRand_closed(const MTRand_closed&); + void operator=(const MTRand_closed&); +}; + +/* Generate 53 bit resolution doubles in the half open interval [0, 1]. */ +class MTRand53 : public MTRand_int32 { +public: + MTRand53(void) : MTRand_int32() {} + MTRand53(unsigned long seed) : MTRand_int32(seed) {} + MTRand53(const unsigned long* seed, int size) : MTRand_int32(seed, size) {} + + double operator()() { + return(static_cast(rand_int32() >> 5) * 67108864. + + static_cast(rand_int32() >> 6)) * (1./9007199254740992.); + } +private: + /* Copy and assignment operators not defined. */ + MTRand53(const MTRand53&); + void operator=(const MTRand53&); +}; + diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..b1874f3 --- /dev/null +++ b/src/object.h @@ -0,0 +1,8 @@ +#pragma once + +class Object { +public: + enum Type { NONE, BODY, SHIP, SPACESTATION, LASER }; + virtual Type GetType(void) = 0; +}; + diff --git a/src/objimport.cpp b/src/objimport.cpp new file mode 100644 index 0000000..37a7ab0 --- /dev/null +++ b/src/objimport.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include "libs.h" +#include "objimport.h" + +ObjMesh* import_obj_mesh(const char *filename) { + char buf[1024]; + FILE* f = fopen(filename, "r"); + if(!f) { + fprintf(stderr, "Failed to load mesh %s\n", filename); + return 0; + } + + ObjMesh* m = new ObjMesh; + float vsum[3]; + memset(vsum, 0, sizeof(float)*3); + + while(fgets(buf, sizeof(buf), f)) { + if(buf[0] == '#') continue; + ObjVertex v; + if(sscanf(buf, "v %f %f %f", &v.p.x, &v.p.y, &v.p.z) == 3) { + m->vertices.push_back(v); + vsum[0] += v.p.x; + vsum[1] += v.p.y; + vsum[2] += v.p.z; + continue; + } + ObjTriangle t; + if(sscanf(buf, "f %d/%*d/ %d/%*d/ %d/%*d/", &t.v[0], &t.v[1], &t.v[2]) == 3) { + t.v[0]--; + t.v[1]--; + t.v[2]--; + m->triangles.push_back(t); + continue; + } + } + vsum[0] /= m->vertices.size(); + vsum[1] /= m->vertices.size(); + vsum[2] /= m->vertices.size(); + + /* Locate the model roughly at 0,0,0. */ + for(unsigned int i = 0; i < m->vertices.size(); i++) { + m->vertices[i].p.x -= vsum[0]; + m->vertices[i].p.y -= vsum[1]; + m->vertices[i].p.z -= vsum[2]; + } + + printf("%zd vertices\n", m->vertices.size()); + printf("%zd triangles\n", m->triangles.size()); + return m; +} + +/* Why not make a display list.. */ +void ObjMesh::Render(void) { + glBegin(GL_TRIANGLES); + for(unsigned int i = 0; i < triangles.size(); i++) { + ObjTriangle& t = triangles[i]; + + vector3f p0 = vertices[t.v[0]].p; + vector3f p1 = vertices[t.v[1]].p; + vector3f p2 = vertices[t.v[2]].p; + + vector3f n = -vector3f::Normalize(vector3f::Cross(p0-p2, p0-p1)); + + glNormal3fv(&n[0]); + glVertex3fv(&vertices[t.v[0]].p[0]); + glVertex3fv(&vertices[t.v[1]].p[0]); + glVertex3fv(&vertices[t.v[2]].p[0]); + } + glEnd(); +} + diff --git a/src/objimport.h b/src/objimport.h new file mode 100644 index 0000000..c658729 --- /dev/null +++ b/src/objimport.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include "vector3.h" + +struct ObjVertex { + vector3f p; +}; + +struct ObjTriangle { + int v[3]; +}; + +struct ObjMesh { + std::vector vertices; + std::vector triangles; + void Render(void); +}; + +ObjMesh* import_obj_mesh(const char* filename); + diff --git a/src/planet.cpp b/src/planet.cpp new file mode 100644 index 0000000..f547249 --- /dev/null +++ b/src/planet.cpp @@ -0,0 +1,77 @@ +#include "libs.h" +#include "planet.h" +#include "frame.h" + +Planet::Planet(StarSystem::SBody::SubType subtype) : Body() { + m_radius = 6378135.0; + m_pos = vector3d(0, 0, 0); + m_geom = dCreateSphere(0, m_radius); + m_subtype = subtype; +} + +Planet::~Planet(void) { + dGeomDestroy(m_geom); +} + +vector3d Planet::GetPosition(void) { + return m_pos; +} + +void Planet::SetPosition(vector3d p) { + m_pos = p; + dGeomSetPosition(m_geom, p.x, p.y, p.z); +} + +void Planet::TransformToModelCoords(const Frame* camFrame) { + vector3d fpos = GetPositionRelTo(camFrame); + glTranslatef(m_pos[0]+fpos.x, m_pos[1]+fpos.y, m_pos[2]+fpos.z); +} + +void Planet::SetRadius(double radius) { + m_radius = radius; + dGeomSphereSetRadius(m_geom, radius); +} + +void Planet::Render(const Frame* a_camFrame) { + static GLUquadricObj* qobj = NULL; + + if(!qobj) qobj = gluNewQuadric(); + + glPushMatrix(); + glDisable(GL_DEPTH_TEST); + + double rad = m_radius; + vector3d fpos = GetPositionRelTo(a_camFrame); + + double apparent_size = rad / fpos.Length(); + double len = fpos.Length(); + + while(len > 10000.0f) { + rad *= 0.25; + fpos = 0.25*fpos; + len *= 0.25; + } + + glTranslatef(fpos.x, fpos.y, fpos.z); + glColor3f(1, 1, 1); + + if(apparent_size < 0.001) { + glDisable(GL_LIGHTING); + glPointSize(1.0); + glBegin(GL_POINTS); + glVertex3f(0, 0, 0); + glEnd(); + glEnable(GL_LIGHTING); + } else { + gluSphere(qobj, rad, 100, 100); + } + glEnable(GL_DEPTH_TEST); + glPopMatrix(); +} + +void Planet::SetFrame(Frame* f) { + if(GetFrame()) GetFrame()->RemoveGeom(m_geom); + Body::SetFrame(f); + if(f) f->AddGeom(m_geom); +} + diff --git a/src/planet.h b/src/planet.h new file mode 100644 index 0000000..c56f2f7 --- /dev/null +++ b/src/planet.h @@ -0,0 +1,24 @@ +#pragma once +#include "body.h" +#include "star_system.h" + +class Frame; +class Planet : public Body { +public: + Planet(StarSystem::SBody::SubType); + virtual ~Planet(void); + virtual void SetPosition(vector3d p); + virtual vector3d GetPosition(void); + void SetRadius(double radius); + double GetRadius(void) { return m_radius; } + virtual void Render(const Frame* camFrame); + virtual void TransformToModelCoords(const Frame* camFrame); + virtual void TransformCameraTo(void) {}; + virtual void SetFrame(Frame* f); +private: + vector3d m_pos; + double m_radius; + dGeomID m_geom; + StarSystem::SBody::SubType m_subtype; +}; + diff --git a/src/player.cpp b/src/player.cpp new file mode 100644 index 0000000..82e2fa4 --- /dev/null +++ b/src/player.cpp @@ -0,0 +1,231 @@ +#include "l3d.h" +#include "player.h" +#include "frame.h" +#include "space.h" +#include "gui.h" +#include "world_view.h" +#include "space_station_view.h" + +#define DEG_2_RAD 0.0174532925 + +Player::Player(void) : Ship() { + m_external_view_rotx = m_external_view_roty = 0; + m_external_view_dist = 200; +} + +void Player::Render(const Frame* camFrame) { + if(L3D::GetCamType() == L3D::CAM_EXTERNAL) { + Ship::Render(camFrame); + } else { + glPushMatrix(); + /* Could only rotate, since transform is zero (camFrame is at player origin). */ + TransformToModelCoords(camFrame); + RenderLaserfire(); + glPopMatrix(); + } +} + +void Player::SetDockedWith(SpaceStation* s) { + Ship::SetDockedWith(s); + if(s) { + L3D::SetView(L3D::spaceStationView); + } +} + +vector3d Player::GetExternalViewTranslation(void) { + vector3d p = vector3d(0, 0, m_external_view_dist); + p = matrix4x4d::RotateXMatrix(-DEG_2_RAD*m_external_view_rotx) * p; + p = matrix4x4d::RotateYMatrix(-DEG_2_RAD*m_external_view_roty) * p; + matrix4x4d m; + GetRotMatrix(m); + p = m*p; + //printf("%f,%f,%f\n", p.x, p.y, p.z); + return p; +} + +void Player::ApplyExternalViewRotation(void) { + //glTranslatef(0, 0, m_external_view_dist); + glRotatef(-m_external_view_rotx, 1, 0, 0); + glRotatef(-m_external_view_roty, 0, 1, 0); +} + +#define MOUSE_ACCEL 400 + +void Player::AITurn(void) { + int mouseMotion[2]; + float time_step = L3D::GetTimeStep(); + float ts2 = time_step*time_step; + + if(time_step == 0) return; + if(GetDockedWith()) return; + + L3D::GetMouseMotion(mouseMotion); + float mx, my; + mx = -mouseMotion[0]*time_step*MOUSE_ACCEL; + my = mouseMotion[1]*time_step*MOUSE_ACCEL; + + ClearThrusterState(); + if(L3D::KeyState(SDLK_w)) SetThrusterState(ShipType::THRUSTER_REAR, 1.0f); + if(L3D::KeyState(SDLK_s)) SetThrusterState(ShipType::THRUSTER_FRONT, 1.0f); + if(L3D::KeyState(SDLK_2)) SetThrusterState(ShipType::THRUSTER_TOP, 1.0f); + if(L3D::KeyState(SDLK_x)) SetThrusterState(ShipType::THRUSTER_BOTTOM,1.0f); + if(L3D::KeyState(SDLK_a)) SetThrusterState(ShipType::THRUSTER_LEFT, 1.0f); + if(L3D::KeyState(SDLK_d)) SetThrusterState(ShipType::THRUSTER_RIGHT, 1.0f); + + if(L3D::KeyState(SDLK_SPACE)) SetGunState(0,1); + else SetGunState(0,0); + + /* No torques at huge time accels -- ODE hates it. */ + if(time_step <= 10) { + /* + * Dividing by time step so controls don't go totally mental when + * used at 10x accel. + */ + mx /= ts2; + my /= ts2; + if(L3D::MouseButtonState(3) && (mouseMotion[0] || mouseMotion[1])) { + SetAngThrusterState(1, mx); + SetAngThrusterState(0, my); + } else if(L3D::GetCamType() != L3D::CAM_EXTERNAL) { + float tq = 100/ts2; + float ax = 0; + float ay = 0; + if(L3D::KeyState(SDLK_LEFT)) ay += 1; + if(L3D::KeyState(SDLK_RIGHT)) ay += -1; + if(L3D::KeyState(SDLK_UP)) ax += -1; + if(L3D::KeyState(SDLK_DOWN)) ax += 1; + SetAngThrusterState(2, 0); + SetAngThrusterState(1, ay); + SetAngThrusterState(0, ax); + } + + /* Rotation damping. */ + vector3d angDrag = GetAngularMomentum() * time_step; + dBodyAddTorque(m_body, -angDrag.x, -angDrag.y, -angDrag.z); + } + if(time_step > 10) { + dBodySetAngularVel(m_body, 0, 0, 0); + SetAngThrusterState(0, 0.0f); + SetAngThrusterState(1, 0.0f); + SetAngThrusterState(2, 0.0f); + } + if(L3D::GetCamType() == L3D::CAM_EXTERNAL) { + if(L3D::KeyState(SDLK_UP)) m_external_view_rotx -= 1; + if(L3D::KeyState(SDLK_DOWN)) m_external_view_rotx += 1; + if(L3D::KeyState(SDLK_LEFT)) m_external_view_roty -= 1; + if(L3D::KeyState(SDLK_EQUALS)) m_external_view_dist -= 10; + if(L3D::KeyState(SDLK_MINUS)) m_external_view_dist += 10; + m_external_view_dist = MAX(50, m_external_view_dist); + } + Ship::AITurn(); +} + +#define HUD_CROSSHAIR_SIZE 24.0f + +void Player::DrawHUD(const Frame* cam_frame) { + GLdouble modelMatrix[16]; + GLdouble projMatrix[16]; + GLint viewport[4]; + + glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); + glGetIntegerv(GL_VIEWPORT, viewport); + + const dReal* vel = dBodyGetLinearVel(m_body); + + const matrix4x4d& rot = L3D::world_view->viewingRotation; + vector3d loc_v = rot*vector3d(vel[0], vel[1], vel[2]); + + Gui::Screen::EnterOrtho(); + glColor3f(.7, .7, .7); + + { + for(std::list::iterator i = Space::bodies.begin(); i != Space::bodies.end(); ++i) { + Body* b = *i; + if(b == this) continue; + vector3d _pos = b->GetPositionRelTo(cam_frame); + vector3d cam_coord = rot*_pos; + + if(cam_coord.z < 0) + if(Gui::Screen::Project(_pos.x, _pos.y, _pos.z, modelMatrix, projMatrix, + viewport, &_pos.x, &_pos.y, &_pos.z)) { + Gui::Screen::RenderLabel(b->GetLabel(), _pos.x, _pos.y); + } + } + } + GLdouble pos[3]; + + const float sz = HUD_CROSSHAIR_SIZE; + /* If velocity vector is in front ofus. Draw indicator. */ + if(loc_v.z < 0) { + if(Gui::Screen::Project(vel[0],vel[1],vel[2], modelMatrix, projMatrix, viewport, + &pos[0], &pos[1], &pos[2])) { + glBegin(GL_LINES); + glVertex2f(pos[0]-sz, pos[1]-sz); + glVertex2f(pos[0]-0.5*sz, pos[1]-0.5*sz); + + glVertex2f(pos[0]+sz, pos[1]-sz); + glVertex2f(pos[0]+0.5*sz, pos[1]-0.5*sz); + + glVertex2f(pos[0]+sz, pos[1]+sz); + glVertex2f(pos[0]+0.5*sz, pos[1]+0.5*sz); + + glVertex2f(pos[0]-sz, pos[1]+sz); + glVertex2f(pos[0]-0.5*sz, pos[1]+0.5*sz); + glEnd(); + } + } + + if(L3D::GetCamType() == L3D::CAM_FRONT) { + /* Normal crosshairs. */ + float px = Gui::Screen::GetWidth()/2.0; + float py = Gui::Screen::GetHeight()/2.0; + glBegin(GL_LINES); + glVertex2f(px-sz, py); + glVertex2f(px-0.5*sz, py); + + glVertex2f(px+sz, py); + glVertex2f(px+0.5*sz, py); + + glVertex2f(px, py-sz); + glVertex2f(px, py-0.5*sz); + + glVertex2f(px, py+sz); + glVertex2f(px, py+0.5*sz); + glEnd(); + } + + { + char buf[1024]; + glPushMatrix(); + glTranslatef(0, 440, 0); + vector3d pos = GetPosition(); + vector3d abs_pos = GetPositionRelTo(Space::GetRootFrame()); + const char* rel_to = (GetFrame() ? GetFrame()->GetLabel() : "System"); + snprintf(buf, sizeof(buf), "Pos: %.1f,%.1f,%.1f\n" + "AbsPos: %.1f,%.1f,%.1f\n" + "Rel-to: %s", + pos.x, pos.y, pos.z, + abs_pos.x, abs_pos.y, abs_pos.z, + rel_to); + Gui::Screen::RenderString(buf); + glPopMatrix(); + } + + { + double _vel = sqrt(vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]); + char buf[128]; + if(_vel > 1000) { + snprintf(buf, sizeof(buf), "Velocity: %.2f km/s", _vel*0.001); + } else { + snprintf(buf, sizeof(buf), "Velocity: %.0f m/s", _vel); + } + glPushMatrix(); + glTranslatef(2, 66, 0); + Gui::Screen::RenderString(buf); + glPopMatrix(); + } + + Gui::Screen::LeaveOrtho(); +} + diff --git a/src/rigid_body.cpp b/src/rigid_body.cpp new file mode 100644 index 0000000..00bde01 --- /dev/null +++ b/src/rigid_body.cpp @@ -0,0 +1,35 @@ +#include "libs.h" +#include "rigid_body.h" +#include "space.h" +#include "objimport.h" +#include "frame.h" + +RigidBody::RigidBody(void) : StaticRigidBody() { + m_flags = Body::FLAG_CAN_MOVE_FRAME; + m_body = dBodyCreate(Space::world); + dMassSetBox(&m_mass, 1, 50, 50, 50); + dMassAdjust(&m_mass, 1.0f); + + dBodySetMass(m_body, &m_mass); + dGeomSetBody(m_geom, m_body); + SetPosition(vector3d(0,0,0)); +} + +vector3d RigidBody::GetAngularMomentum(void) { + matrix4x4d I; + I.LoadFromOdeMatrix(m_mass.I); + return I * vector3d(dBodyGetAngularVel(m_body)); +} + +RigidBody::~RigidBody(void) { + dBodyDestroy(m_body); +} + +void RigidBody::SetVelocity(vector3d v) { + dBodySetLinearVel(m_body, v.x, v.y, v.z); +} + +void RigidBody::SetAngVelocity(vector3d v) { + dBodySetAngularVel(m_body, v.x, v.y, v.z); +} + diff --git a/src/rigid_body.h b/src/rigid_body.h new file mode 100644 index 0000000..6aae5ac --- /dev/null +++ b/src/rigid_body.h @@ -0,0 +1,26 @@ +#pragma once +#include "body.h" +#include "static_rigid_body.h" +#include "vector3.h" +#include "matrix4x4.h" + +class ObjMesh; + +class RigidBody: public StaticRigidBody { +public: + RigidBody(void); + virtual ~RigidBody(void); + void SetVelocity(vector3d v); + void SetAngVelocity(vector3d v); + void SetMesh(ObjMesh* m); + virtual bool OnCollision(Body* b) { return true; } + vector3d GetAngularMomentum(void); + + dBodyID m_body; + dMass m_mass; + +protected: + +private: + ObjMesh* m_mesh; +}; diff --git a/src/sbre/Makefile.am b/src/sbre/Makefile.am new file mode 100644 index 0000000..6bd15db --- /dev/null +++ b/src/sbre/Makefile.am @@ -0,0 +1,6 @@ +# Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libsbre.a +libsbre_a_SOURCES = brender.cpp models.cpp primfunc.cpp simtriang.cpp transp.cpp jjvector.cpp + +include_HEADERS = fastmath.h sbre.h sbre_int.h sbre_anim.h jjtypes.h jjvector.h diff --git a/src/sbre/brender.cpp b/src/sbre/brender.cpp new file mode 100644 index 0000000..5225347 --- /dev/null +++ b/src/sbre/brender.cpp @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include "sbre.h" +#include "sbre_int.h" +#include "sbre_anim.h" + +float ResolveAnim(ObjParams* pObjParam, uint16 type) { + const AnimFunc* pFunc = pAFunc+type; + float anim = pObjParam->pAnim[pFunc->src]; + anim = anim*anim*anim*pFunc->order3 + anim*anim*pFunc->order2 + + anim*pFunc->order1 + pFunc->order0; + + if(pFunc->mod == AMOD_REF) { + anim = fmod(anim, 2.002f); + if(anim > 1.0f) anim = 2.002f - anim; + } else if(pFunc->mod == AMOD_MOD1) anim = fmod(anim, 1.001f); + + if(anim < 0.0f) anim = 0.0f; + if(anim > 1.0f) anim = 1.0f; + return anim; +} + +static Vector pUnitVec[6] = { + { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, + { -1.0f, 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, { 0.0f, 0.0f, -1.0f }, +}; + +static void ResolveVertices(Model* pMod, Vector* pRes, ObjParams* pObjParam) { + Vector* pCur = pRes; + Vector tv1, tv2, xax, yax; + float anim; + + int i; for(i=0; i < 6; i++) *(pCur++) = pUnitVec[i]; + + PlainVertex* pPVtx = pMod->pPVtx; + for(i = 0; i < pMod->numPVtx-6; i++, pCur++, pPVtx++) { + switch(pPVtx->type) { + case VTYPE_PLAIN: *pCur = pPVtx->pos; break; + case VTYPE_DIR: VecNorm(&pPVtx->pos, pCur); break; + } + } + + pCur = pRes + pMod->cvStart; + CompoundVertex* pCVtx = pMod->pCVtx; + for(i = 0; i < pMod->numCVtx; i++, pCur++, pCVtx++) { + switch(pCVtx->type) { + case VTYPE_NORM: + VecSub(pRes+pCVtx->pParam[2], pRes+pCVtx->pParam[1], &tv1); + VecSub(pRes+pCVtx->pParam[0], pRes+pCVtx->pParam[1], &tv2); + VecCross(&tv1, &tv2, pCur); + VecNorm(pCur, pCur); + break; + case VTYPE_CROSS: + VecCross(pRes+pCVtx->pParam[0], pRes+pCVtx->pParam[1], pCur); + VecNorm(pCur, pCur); + break; + case VTYPE_ANIMLIN: + anim = ResolveAnim(pObjParam, pCVtx->pParam[4]); + *pCur = pRes[pCVtx->pParam[0]]; + VecSub(pRes+pCVtx->pParam[1], pCur, &tv1); + VecMul(&tv1, anim, &tv1); + VecAdd(&tv1, pCur, pCur); + break; + case VTYPE_ANIMCUBIC: + anim = ResolveAnim(pObjParam, pCVtx->pParam[4]); + ResolveCubicSpline(pRes+pCVtx->pParam[0], pRes+pCVtx->pParam[1], + pRes+pCVtx->pParam[2], pRes+pCVtx->pParam[3], anim, pCur); + break; + case VTYPE_ANIMHERM: + anim = ResolveAnim(pObjParam, pCVtx->pParam[4]); + ResolveHermiteSpline(pRes+pCVtx->pParam[0], pRes+pCVtx->pParam[1], + pRes+pCVtx->pParam[2], pRes+pCVtx->pParam[3], anim, pCur); + break; + case VTYPE_ANIMROTATE: + anim = ResolveAnim(pObjParam, pCVtx->pParam[4]) * 2.0f * 3.141592f; + xax = pRes[pCVtx->pParam[1]]; + VecCross(pRes+pCVtx->pParam[0], &xax, &yax); + VecMul(&xax, sin(anim), &tv1); + VecMul(&yax, cos(anim), &tv2); + VecAdd(&tv1, &tv2, pCur); + break; + default: *pCur = zero_vector; break; + } + } +} + +static float g_dn, g_df; +static int g_wireframe = 0; + +void sbreSetViewport(int w, int h, int d, float zn, float zf, float dn, float df) { + glViewport(0, 0, w, h); + + float pProjMat[16] = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f }; + + pProjMat[ 0] = (2.0f*d)/w; + pProjMat[ 5] = (2.0f*d)/h; + pProjMat[10] = (zf+zn)/(zf-zn); + pProjMat[14] = (-2.0f*zn*zf)/(zf-zn); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(pProjMat); + glDepthRange(dn+SBRE_ZBIAS, df); + g_dn = dn; g_df = df; +} + +void sbreSetDirLight(float* pColor, float* pDir) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + float pColor4[4] = { 0, 0, 0, 1.0f }; + float pDir4[4] = { pDir[0], pDir[1], pDir[2], 0.0f }; + for(int i = 0; i < 3; i++) pColor4[i] = SBRE_AMB + pColor[i] * (1.0f-SBRE_AMB); + + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0, GL_POSITION, pDir4); + glLightfv(GL_LIGHT0, GL_DIFFUSE, pColor4); + glLightfv(GL_LIGHT0, GL_SPECULAR, pColor4); +} + +void sbreSetWireframe(int val) { + g_wireframe = val; +} + +void SetGeneralState(void) { + float ambient[4] = { SBRE_AMB, SBRE_AMB, SBRE_AMB, 1.0f }; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); + + glDisable(GL_TEXTURE_2D); + glFrontFace(GL_CW); + glEnable(GL_DEPTH_TEST); + + if(g_wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_CULL_FACE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_CULL_FACE); + } + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); +} + +void SetOpaqueState(void) { + glDisable(GL_BLEND); + glEnable(GL_LIGHTING); + glEnable(GL_NORMALIZE); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); +} + +void SetTransState(void) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_LIGHTING); + glDisable(GL_NORMALIZE); + + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} + +void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam, + float s, Vector* pCompos) { + Model* pModel = ppModel[model]; + s *= pModel->scale; + float pMV[16]; + pMV[ 0] = s*pOrient->x1; pMV[1] = s*pOrient->y1; pMV[ 2] = s*pOrient->z1; pMV[ 3] = 0.0f; + pMV[ 4] = s*pOrient->x2; pMV[5] = s*pOrient->y2; pMV[ 6] = s*pOrient->z2; pMV[ 7] = 0.0f; + pMV[ 8] = s*pOrient->x3; pMV[9] = s*pOrient->y3; pMV[10] = s*pOrient->z3; pMV[11] = 0.0f; + pMV[12] = pPos->x; pMV[13] = pPos->y; pMV[14] = pPos->z; pMV[15] = 1.0f; + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(pMV); + + Vector* pVtx = (Vector*)alloca(sizeof(Vector)*(pModel->cvStart+pModel->numCVtx)); + + ResolveVertices(pModel, pVtx, pParam); + + RState rstate; + rstate.pVtx = pVtx; + rstate.objpos = *pPos; + rstate.objorient = *pOrient; + rstate.scale = s; + rstate.pModel = pModel; + rstate.pObjParam = pParam; + rstate.dn = g_dn; + rstate.df = g_df; + MatTVecMult(pOrient, pPos, &rstate.campos); + VecInv(&rstate.campos, &rstate.campos); + if(pCompos) rstate.compos = *pCompos; + else rstate.compos = zero_vector; + + if(pModel->numCache && !pModel->ppVCache) { + pModel->pNumVtx = (int*)calloc(pModel->numCache, sizeof(int)); + pModel->pNumIdx = (int*)calloc(pModel->numCache, sizeof(int)); + pModel->ppVCache = (Vector**)calloc(pModel->numCache, sizeof(Vector*)); + pModel->ppICache = (uint16**)calloc(pModel->numCache, sizeof(uint16*)); + } + + SetGeneralState(); + SetOpaqueState(); + + uint16* pData = pModel->pData; + while(*pData != PTYPE_END) { + pData += pPrimFuncTable[*pData & 0xff] (pData, pModel, &rstate); + } + + SetTransState(); + RenderTransparencies(&rstate); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_CULL_FACE); +} + diff --git a/src/sbre/fastmath.h b/src/sbre/fastmath.h new file mode 100644 index 0000000..45b3ded --- /dev/null +++ b/src/sbre/fastmath.h @@ -0,0 +1,80 @@ +#pragma once + +extern int g_pInvTable[64]; +extern int g_pInvTableLow[64]; +extern int g_pInvTableHigh[64]; + +extern int g_pSqrtTable[64]; +extern int g_pSqrtTableLow[64]; +extern int g_pSqrtTableHigh[64]; + +extern int g_pISqrtTable[64]; +extern int g_pISqrtTableLow[64]; +extern int g_pISqrtTableHigh[64]; + + +inline float FastInv(float f) { + int exp = 0x7e800000 - (0x7f800000 & *(int *)&f); + int mant = g_pInvTable[(*(int *)&f >> 17) & 0x3f]; + int combo = mant | exp | (0x80000000 & *(int *)&f); + return *(float *)&combo; +} + +inline float FastInvLow(float f) { + int exp = 0x7e800000 - (0x7f800000 & *(int *)&f); + int mant = g_pInvTableLow[(*(int *)&f >> 17) & 0x3f]; + int combo = mant | exp | (0x80000000 & *(int *)&f); + return *(float *)&combo; +} + +/* Fractionally off maximum for 2^n input. */ +inline float FastInvHigh(float f) { + int exp = 0x7e800000 - (0x7f800000 & *(int *)&f); + int mant = g_pInvTableHigh[(*(int *)&f >> 17) & 0x3f]; + int combo = mant | exp | (0x80000000 & *(int *)&f); + return *(float *)&combo; +} + +inline float FastSqrt(float f) { + int exp = 0x7f800000 & ((*(int *)&f >> 1) + 0x1fc00000); + int mant = g_pSqrtTable[(*(int *)&f >> 18) & 0x3f] | exp; + return *(float *)&mant; +} + +inline float FastSqrtLow(float f) { + int exp = 0x7f800000 & ((*(int *)&f >> 1) + 0x1fc00000); + int mant = g_pSqrtTableLow[(*(int *)&f >> 18) & 0x3f] | exp; + return *(float *)&mant; +} + +inline float FastSqrtHigh(float f) { + int exp = 0x7f800000 & ((*(int *)&f >> 1) + 0x1fc00000); + int mant = g_pSqrtTableHigh[(*(int *)&f >> 18) & 0x3f] | exp; + return *(float *)&mant; +} + +inline float FastInvSqrt(float f) { + int exp = 0x5e800000 - ((*(int *)&f >> 1) & 0x3f800000); + int mant = g_pISqrtTable[(*(int *)&f >> 18) & 0x3f] + exp; + return *(float *)&mant; +} + +inline float FastInvSqrtLow(float f) { + int exp = 0x5e800000 - ((*(int *)&f >> 1) & 0x3f800000); + int mant = g_pISqrtTableLow[(*(int *)&f >> 18) & 0x3f] + exp; + return *(float *)&mant; +} + +inline float FastInvSqrtHigh (float f) { + int exp = 0x5e800000 - ((*(int *)&f >> 1) & 0x3f800000); + int mant = g_pISqrtTableHigh[(*(int *)&f >> 18) & 0x3f] + exp; + return *(float *)&mant; +} + +inline void VecNormFast(Vector* v1, Vector* res) { + float temp = FastInvSqrt(VecDot (v1, v1)); + res->x = v1->x * temp; + res->y = v1->y * temp; + res->z = v1->z * temp; +} + diff --git a/src/sbre/jjtypes.h b/src/sbre/jjtypes.h new file mode 100644 index 0000000..47cedfe --- /dev/null +++ b/src/sbre/jjtypes.h @@ -0,0 +1,7 @@ +#pragma once + +#include +typedef Uint32 uint32; +typedef Uint16 uint16; +typedef Uint8 uint8; + diff --git a/src/sbre/jjvector.cpp b/src/sbre/jjvector.cpp new file mode 100644 index 0000000..749f9d5 --- /dev/null +++ b/src/sbre/jjvector.cpp @@ -0,0 +1,207 @@ +#include +#include + +#include "jjtypes.h" +#include "jjvector.h" +#include "fastmath.h" + +static Vector xaxis = { 1.0f, 0.0f, 0.0f }; +static Vector yaxis = { 0.0f, 1.0f, 0.0f }; + +void MatToAxisAng(Matrix* m, AxisAng* aa) { + Vector v2 = { m->x2, m->y2, m->z2 }; + aa->v.x = m->x1; aa->v.y = m->y1; aa->v.z = m->z1; + VecNorm(&aa->v, &aa->v); + + Vector axis2, axis3; + float tv = VecDot(&xaxis, &aa->v); + if(tv*tv < 0.5) VecCross(&aa->v, &xaxis, &axis2); + else VecCross(&aa->v, &yaxis, &axis2); + VecNorm(&axis2, &axis2); + VecCross(&aa->v, &axis2, &axis3); + + float ta = VecDot (&v2, &axis2); + //_ASSERTE (ta < 1.0f && ta > -1.0f); + if(ta > 1.0f) ta = 1.0f; + if(ta < -1.0f) ta = -1.0f; + + aa->a = (float) acos (ta); + if(VecDot(&v2, &axis3) < 0.0f) aa->a *= -1.0f; +} + +void AxisAngToMat(AxisAng* aa, Matrix* m) { + Vector v2, v3; + m->x1 = aa->v.x; m->y1 = aa->v.y; m->z1 = aa->v.z; + + Vector axis2, axis3; + float tv = VecDot(&xaxis, &aa->v); + if (tv*tv < 0.5) VecCross(&aa->v, &xaxis, &axis2); + else VecCross(&aa->v, &yaxis, &axis2); + VecNorm(&axis2, &axis2); + VecCross(&aa->v, &axis2, &axis3); + + VecMul(&axis2, cos (aa->a), &axis2); + VecMul(&axis3, sin (aa->a), &axis3); + VecAdd(&axis2, &axis3, &v2); + VecCross(&aa->v, &v2, &v3); + + m->x2 = v2.x; m->y2 = v2.y; m->z2 = v2.z; + m->x3 = v3.x; m->y3 = v3.y; m->z3 = v3.z; +} + + +void MatToQuat(Matrix* m1, Quaternion* res) { + float trace = m1->x1 + m1->y2 + m1->z3 + 1.0f; + if(trace > 0.0f) { + float qs = 0.5f / sqrtf (trace); + res->w = 0.25f / qs; + res->x = (m1->z2 - m1->y3) * qs; + res->y = (m1->x3 - m1->z1) * qs; + res->z = (m1->y1 - m1->x2) * qs; + } else { + if(m1->x1 > m1->y2 && m1->x1 > m1->z3) { + float qs = 2.0f * sqrtf (1.0f + m1->x1 - m1->y2 - m1->z3); + res->x = 0.25f * qs; + res->y = (m1->x2 + m1->y1) / qs; + res->z = (m1->x3 + m1->z1) / qs; + res->w = (m1->z2 - m1->y3) / qs; + } else if(m1->y2 > m1->z3) { + float qs = 2.0f * sqrtf (1.0f + m1->y2 - m1->x1 - m1->z3); + res->x = (m1->x2 + m1->y1) / qs; + res->y = 0.25f * qs; + res->z = (m1->y3 + m1->z2) / qs; + res->w = (m1->x3 - m1->z1) / qs; + } else { + float qs = 2.0f * sqrtf (1.0f + m1->z3 - m1->x1 - m1->y2); + res->x = (m1->x3 + m1->z1) / qs; + res->y = (m1->y3 + m1->z2) / qs; + res->z = 0.25f * qs; + res->w = (m1->y1 - m1->x2) / qs; + } + } +} + +void QuatToMat(Quaternion* q1, Matrix* res) { + double sqw = q1->w*q1->w; + double sqx = q1->x*q1->x; + double sqy = q1->y*q1->y; + double sqz = q1->z*q1->z; + res->x1 = (float)(sqx - sqy - sqz + sqw); + res->y2 = (float)(-sqx + sqy - sqz + sqw); + res->z3 = (float)(-sqx - sqy + sqz + sqw); + + double tmp1 = q1->x*q1->y; + double tmp2 = q1->z*q1->w; + res->y1 = (float)(2.0 * (tmp1 + tmp2)); + res->x2 = (float)(2.0 * (tmp1 - tmp2)); + + tmp1 = q1->x*q1->z; + tmp2 = q1->y*q1->w; + res->z1 = (float)(2.0 * (tmp1 - tmp2)); + res->x3 = (float)(2.0 * (tmp1 + tmp2)); + + tmp1 = q1->y*q1->z; + tmp2 = q1->x*q1->w; + res->z2 = (float)(2.0 * (tmp1 + tmp2)); + res->y3 = (float)(2.0 * (tmp1 - tmp2)); +} + + +int g_pInvTable[64] = { + 0x7e03f8, 0x7a232d, 0x76603e, 0x72b9d6, 0x6f2eb7, 0x6bbdb3, 0x6865ac, 0x652598, + 0x61fc78, 0x5ee95c, 0x5beb62, 0x5901b2, 0x562b81, 0x53680d, 0x50b6a0, 0x4e168a, + 0x4b8728, 0x4907da, 0x46980c, 0x443730, 0x41e4bc, 0x3fa030, 0x3d6910, 0x3b3ee7, + 0x392144, 0x370fbb, 0x3509e7, 0x330f63, 0x311fd4, 0x2f3ade, 0x2d602b, 0x2b8f6a, + 0x29c84a, 0x280a81, 0x2655c4, 0x24a9cf, 0x23065e, 0x216b31, 0x1fd80a, 0x1e4cad, + 0x1cc8e1, 0x1b4c70, 0x19d723, 0x1868c8, 0x17012e, 0x15a025, 0x144581, 0x12f114, + 0x11a2b4, 0x105a38, 0x0f177a, 0x0dda52, 0x0ca29c, 0x0b7034, 0x0a42f8, 0x091ac7, + 0x07f781, 0x06d905, 0x05bf37, 0x04a9fa, 0x039930, 0x028cc0, 0x01848e, 0x008081, +}; + +int g_pInvTableLow[64] = { + 0x7c0fc3, 0x783e11, 0x74898f, 0x70f0f3, 0x6d7305, 0x6a0ea3, 0x66c2b6, 0x638e3a, + 0x60703a, 0x5d67ca, 0x5a740f, 0x579437, 0x54c77c, 0x520d22, 0x4f6476, 0x4cccce, + 0x4a4589, 0x47ce0e, 0x4565ca, 0x430c32, 0x40c0c2, 0x3e82fb, 0x3c5265, 0x3a2e8d, + 0x381704, 0x360b62, 0x340b42, 0x321644, 0x302c0c, 0x2e4c42, 0x2c7692, 0x2aaaac, + 0x28e840, 0x272f06, 0x257eb6, 0x23d70b, 0x2237c4, 0x20a0a1, 0x1f1167, 0x1d89d9, + 0x1c09c1, 0x1a90e9, 0x191f1b, 0x17b427, 0x164fdb, 0x14f20a, 0x139a86, 0x124925, + 0x10fdbd, 0x0fb825, 0x0e7836, 0x0d3dcc, 0x0c08c1, 0x0ad8f4, 0x09ae41, 0x088889, + 0x0767ac, 0x064b8b, 0x053409, 0x042109, 0x03126f, 0x020821, 0x010205, 0x000001, +}; + +int g_pInvTableHigh[64] = { + 0x7fffff, 0x7c0fc1, 0x783e10, 0x74898d, 0x70f0f1, 0x6d7304, 0x6a0ea1, 0x66c2b4, + 0x638e39, 0x607038, 0x5d67c9, 0x5a740e, 0x579436, 0x54c77b, 0x520d21, 0x4f6475, + 0x4ccccd, 0x4a4588, 0x47ce0c, 0x4565c8, 0x430c31, 0x40c0c1, 0x3e82fa, 0x3c5264, + 0x3a2e8c, 0x381703, 0x360b61, 0x340b41, 0x321643, 0x302c0b, 0x2e4c41, 0x2c7692, + 0x2aaaab, 0x28e83f, 0x272f05, 0x257eb5, 0x23d70a, 0x2237c3, 0x20a0a1, 0x1f1166, + 0x1d89d9, 0x1c09c1, 0x1a90e8, 0x191f1a, 0x17b426, 0x164fda, 0x14f209, 0x139a86, + 0x124925, 0x10fdbc, 0x0fb824, 0x0e7835, 0x0d3dcb, 0x0c08c1, 0x0ad8f3, 0x09ae41, + 0x088889, 0x0767ab, 0x064b8a, 0x053408, 0x042108, 0x03126f, 0x020821, 0x010204, +}; + +int g_pSqrtTable[64] = { + 0x366d96, 0x3936a1, 0x3bf51b, 0x3ea979, 0x415428, 0x43f58d, 0x468e06, 0x491dec, + 0x4ba592, 0x4e2545, 0x509d4e, 0x530df3, 0x557775, 0x57da10, 0x5a35fe, 0x5c8b77, + 0x5edaae, 0x6123d4, 0x636719, 0x65a4a9, 0x67dcae, 0x6a0f50, 0x6c3cb7, 0x6e6507, + 0x708862, 0x72a6ea, 0x74c0c0, 0x76d603, 0x78e6ce, 0x7af340, 0x7cfb72, 0x7eff7f, + 0x00ff02, 0x02f734, 0x04e7ee, 0x06d182, 0x08b43d, 0x0a9067, 0x0c6641, 0x0e360b, + 0x100000, 0x11c456, 0x138341, 0x153cf2, 0x16f196, 0x18a15a, 0x1a4c65, 0x1bf2df, + 0x1d94ec, 0x1f32af, 0x20cc4a, 0x2261dc, 0x23f383, 0x25815a, 0x270b7f, 0x28920a, + 0x2a1514, 0x2b94b5, 0x2d1104, 0x2e8a16, 0x300000, 0x3172d6, 0x32e2ac, 0x344f93, +}; + +int g_pSqrtTableLow[64] = { + 0x3504f3, 0x37d375, 0x3a9728, 0x3d5087, 0x400000, 0x42a5fe, 0x4542e1, 0x47d706, + 0x4a62c2, 0x4ce665, 0x4f623a, 0x51d689, 0x544395, 0x56a99b, 0x5908d9, 0x5b6186, + 0x5db3d7, 0x600000, 0x624630, 0x648695, 0x66c15a, 0x68f6a9, 0x6b26a9, 0x6d517f, + 0x6f7751, 0x71983e, 0x73b46a, 0x75cbf2, 0x77def6, 0x79ed91, 0x7bf7df, 0x7dfdfc, + 0x000000, 0x01fc10, 0x03f07b, 0x05dd98, 0x07c3b6, 0x09a320, 0x0b7c1a, 0x0d4ee4, + 0x0f1bbd, 0x10e2dc, 0x12a476, 0x1460be, 0x1617e3, 0x17ca11, 0x197774, 0x1b2032, + 0x1cc471, 0x1e6455, 0x200000, 0x219792, 0x232b2b, 0x24bae7, 0x2646e1, 0x27cf36, + 0x2953fd, 0x2ad550, 0x2c5345, 0x2dcdf3, 0x2f456f, 0x30b9cc, 0x322b20, 0x33997c, +}; + +int g_pSqrtTableHigh[64] = { + 0x37d374, 0x3a9728, 0x3d5086, 0x3fffff, 0x42a5fd, 0x4542e1, 0x47d705, 0x4a62c1, + 0x4ce664, 0x4f623a, 0x51d689, 0x544394, 0x56a99b, 0x5908d8, 0x5b6185, 0x5db3d7, + 0x5fffff, 0x62462f, 0x648694, 0x66c15a, 0x68f6a8, 0x6b26a8, 0x6d517f, 0x6f7750, + 0x71983e, 0x73b469, 0x75cbf2, 0x77def5, 0x79ed90, 0x7bf7df, 0x7dfdfb, 0x7fffff, + 0x01fc0f, 0x03f07b, 0x05dd98, 0x07c3b6, 0x09a31f, 0x0b7c19, 0x0d4ee4, 0x0f1bbc, + 0x10e2db, 0x12a475, 0x1460bd, 0x1617e2, 0x17ca11, 0x197773, 0x1b2031, 0x1cc470, + 0x1e6454, 0x200000, 0x219792, 0x232b2b, 0x24bae6, 0x2646e1, 0x27cf35, 0x2953fd, + 0x2ad550, 0x2c5345, 0x2dcdf3, 0x2f456e, 0x30b9cc, 0x322b20, 0x33997c, 0x3504f3, +}; + +int g_pISqrtTable[64] = { + 0xb39f19, 0xb0eb96, 0xae565c, 0xabdd46, 0xa97e62, 0xa737f0, 0xa50855, 0xa2ee1d, + 0xa0e7f5, 0x9ef4a4, 0x9d130e, 0x9b422c, 0x99810c, 0x97ced0, 0x962aa9, 0x9493d9, + 0x9309af, 0x918b87, 0x9018c6, 0x8eb0e0, 0x8d534f, 0x8bff97, 0x8ab544, 0x8973e8, + 0x883b1e, 0x870a87, 0x85e1c7, 0x84c08b, 0x83a682, 0x829362, 0x8186e2, 0x8080c1, + 0x7e05ec, 0x7a33f9, 0x768cdc, 0x730d8a, 0x6fb345, 0x6c7b90, 0x69642a, 0x666b02, + 0x638e39, 0x60cc16, 0x5e2305, 0x5b9193, 0x59166b, 0x56b051, 0x545e22, 0x521ed0, + 0x4ff162, 0x4dd4ed, 0x4bc89b, 0x49cba2, 0x47dd45, 0x45fcd6, 0x4429af, 0x426337, + 0x40a8de, 0x3efa1c, 0x3d5671, 0x3bbd67, 0x3a2e8c, 0x38a975, 0x372dbf, 0x35bb09, +}; + +int g_pISqrtTableLow[64] = { + 0xb2416a, 0xaf9d54, 0xad166d, 0xaaaaab, 0xa85836, 0xa61d60, 0xa3f8a3, 0xa1e89c, + 0x9fec04, 0x9e01b3, 0x9c2896, 0x9a5fb2, 0x98a61f, 0x96fb07, 0x955da2, 0x93cd3b, + 0x924925, 0x90d0c3, 0x8f6381, 0x8e00d5, 0x8ca840, 0x8b5948, 0x8a137e, 0x88d677, + 0x87a1d2, 0x867532, 0x85503e, 0x8432a5, 0x831c1a, 0x820c53, 0x81030a, 0x800000, + 0x7c1765, 0x785b43, 0x74c868, 0x715bf0, 0x6e133f, 0x6aebf6, 0x67e3ee, 0x64f92f, + 0x6229ed, 0x5f7483, 0x5cd76e, 0x5a514a, 0x57e0cf, 0x5584ce, 0x533c2e, 0x5105ec, + 0x4ee116, 0x4ccccd, 0x4ac840, 0x48d2ac, 0x46eb5b, 0x4511a3, 0x4344e7, 0x418490, + 0x3fd012, 0x3e26ec, 0x3c88a0, 0x3af4bb, 0x396acf, 0x37ea74, 0x36734a, 0x3504f4, +}; + +int g_pISqrtTableHigh[64] = { + 0xb504f3, 0xb2416a, 0xaf9d53, 0xad166c, 0xaaaaab, 0xa85835, 0xa61d5f, 0xa3f8a2, + 0xa1e89b, 0x9fec04, 0x9e01b3, 0x9c2896, 0x9a5fb2, 0x98a61f, 0x96fb06, 0x955da2, + 0x93cd3a, 0x924925, 0x90d0c3, 0x8f6381, 0x8e00d5, 0x8ca83f, 0x8b5948, 0x8a137d, + 0x88d677, 0x87a1d2, 0x867532, 0x85503e, 0x8432a5, 0x831c1a, 0x820c52, 0x81030a, + 0x800000, 0x7c1764, 0x785b42, 0x74c867, 0x715bef, 0x6e133e, 0x6aebf5, 0x67e3ed, + 0x64f92e, 0x6229ed, 0x5f7483, 0x5cd76e, 0x5a514a, 0x57e0cf, 0x5584cd, 0x533c2e, + 0x5105ec, 0x4ee116, 0x4ccccd, 0x4ac83f, 0x48d2ab, 0x46eb5a, 0x4511a3, 0x4344e6, + 0x41848f, 0x3fd012, 0x3e26eb, 0x3c889f, 0x3af4ba, 0x396ace, 0x37ea74, 0x36734a, +}; diff --git a/src/sbre/jjvector.h b/src/sbre/jjvector.h new file mode 100644 index 0000000..713be1a --- /dev/null +++ b/src/sbre/jjvector.h @@ -0,0 +1,521 @@ +#pragma once +#include + +#define JJM_PI 3.141592653589793 +#define JJM_FPI 3.1415926f + +struct Vector { + float x, y, z; +}; + +struct DVector { + double x, y, z; +}; + +struct Quaternion { + float w, x, y, z; +}; + +struct AxisAng { + Vector v; + float a; +}; + +struct Plane64 { + DVector norm; + double dist; +}; + +struct Matrix { + float x1, x2, x3; /* _11, _12, _13 */ + float y1, y2, y3; /* _21, _22, _23 */ + float z1, z2, z3; /* _31, _32, _33 */ +}; + +struct DMatrix { + double x1, x2, x3; /* _11, _12, _13 */ + double y1, y2, y3; /* _21, _22, _23 */ + double z1, z2, z3; /* _31, _32, _33 */ +}; + +const Vector zero_vector = { 0, 0, 0 }; +const DVector zero_dvector = { 0, 0, 0 }; +const Matrix identity_matrix = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; +const DMatrix identity_dmatrix = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + +/* Conversion functions. */ +inline void DVecToVec(DVector* v1, Vector* v2) { + v2->x = (float)v1->x; + v2->y = (float)v1->y; + v2->z = (float)v1->z; +} + +inline void VecToDVec(Vector* v1, DVector* v2) { + v2->x = v1->x; + v2->y = v1->y; + v2->z = v1->z; +} + +inline void DMatToMat(DMatrix* m1, Matrix* m2) { + m2->x1 = (float)m1->x1; + m2->x2 = (float)m1->x2; + m2->x3 = (float)m1->x3; + m2->y1 = (float)m1->y1; + m2->y2 = (float)m1->y2; + m2->y3 = (float)m1->y3; + m2->z1 = (float)m1->z1; + m2->z2 = (float)m1->z2; + m2->z3 = (float)m1->z3; +} + +inline void MatToDMat(Matrix* m1, DMatrix* m2) { + m2->x1 = m1->x1; + m2->x2 = m1->x2; + m2->x3 = m1->x3; + m2->y1 = m1->y1; + m2->y2 = m1->y2; + m2->y3 = m1->y3; + m2->z1 = m1->z1; + m2->z2 = m1->z2; + m2->z3 = m1->z3; +} + +inline void DMatTrans(DMatrix* m1, DMatrix* m2) { + m2->x1 = m1->x1; + m2->x2 = m1->y1; + m2->x3 = m1->z1; + m2->y1 = m1->x2; + m2->y2 = m1->y2; + m2->y3 = m1->z2; + m2->z1 = m1->x3; + m2->z2 = m1->y3; + m2->z3 = m1->z3; +} + +inline void VecSet(float x, float y, float z, Vector* res) { + res->x = x; + res->y = y; + res->z = z; +} + +inline void DVecSet(double x, double y, double z, DVector* res) { + res->x = x; + res->y = y; + res->z = z; +} + +inline void VecRotate(Vector* v, Vector* res) { + res->x = v->y; res->y = v->z; res->z = v->x; +} + +inline void VecRotate(DVector* v, DVector* res) { + res->x = v->y; res->y = v->z; res->z = v->x; +} + +void MatToAxisAng(Matrix* m, AxisAng* aa); +void AxisAngToMat(AxisAng* aa, Matrix* m); + +void MatToQuat(Matrix* m1, Quaternion* res); +void QuatToMat(Quaternion* q1, Matrix* res); + + +/* + * MatMult, MatTMult, VecCross and FindNormal will break if + * called with output and input objects the same. + */ + +/* Actual functions, maybe */ +inline void MatMatMult(Matrix* m1, Matrix* m2, Matrix* res) { + res->x1 = m1->x1*m2->x1 + m1->x2*m2->y1 + m1->x3*m2->z1; + res->x2 = m1->x1*m2->x2 + m1->x2*m2->y2 + m1->x3*m2->z2; + res->x3 = m1->x1*m2->x3 + m1->x2*m2->y3 + m1->x3*m2->z3; + + res->y1 = m1->y1*m2->x1 + m1->y2*m2->y1 + m1->y3*m2->z1; + res->y2 = m1->y1*m2->x2 + m1->y2*m2->y2 + m1->y3*m2->z2; + res->y3 = m1->y1*m2->x3 + m1->y2*m2->y3 + m1->y3*m2->z3; + + res->z1 = m1->z1*m2->x1 + m1->z2*m2->y1 + m1->z3*m2->z1; + res->z2 = m1->z1*m2->x2 + m1->z2*m2->y2 + m1->z3*m2->z2; + res->z3 = m1->z1*m2->x3 + m1->z2*m2->y3 + m1->z3*m2->z3; +} + +inline void DMatDMatMult(DMatrix* m1, DMatrix* m2, DMatrix* res) { + res->x1 = m1->x1*m2->x1 + m1->x2*m2->y1 + m1->x3*m2->z1; + res->x2 = m1->x1*m2->x2 + m1->x2*m2->y2 + m1->x3*m2->z2; + res->x3 = m1->x1*m2->x3 + m1->x2*m2->y3 + m1->x3*m2->z3; + + res->y1 = m1->y1*m2->x1 + m1->y2*m2->y1 + m1->y3*m2->z1; + res->y2 = m1->y1*m2->x2 + m1->y2*m2->y2 + m1->y3*m2->z2; + res->y3 = m1->y1*m2->x3 + m1->y2*m2->y3 + m1->y3*m2->z3; + + res->z1 = m1->z1*m2->x1 + m1->z2*m2->y1 + m1->z3*m2->z1; + res->z2 = m1->z1*m2->x2 + m1->z2*m2->y2 + m1->z3*m2->z2; + res->z3 = m1->z1*m2->x3 + m1->z2*m2->y3 + m1->z3*m2->z3; +} + +inline void MatTMatMult(Matrix* m1, Matrix* m2, Matrix* res) { + res->x1 = m1->x1*m2->x1 + m1->y1*m2->y1 + m1->z1*m2->z1; + res->x2 = m1->x1*m2->x2 + m1->y1*m2->y2 + m1->z1*m2->z2; + res->x3 = m1->x1*m2->x3 + m1->y1*m2->y3 + m1->z1*m2->z3; + + res->y1 = m1->x2*m2->x1 + m1->y2*m2->y1 + m1->z2*m2->z1; + res->y2 = m1->x2*m2->x2 + m1->y2*m2->y2 + m1->z2*m2->z2; + res->y3 = m1->x2*m2->x3 + m1->y2*m2->y3 + m1->z2*m2->z3; + + res->z1 = m1->x3*m2->x1 + m1->y3*m2->y1 + m1->z3*m2->z1; + res->z2 = m1->x3*m2->x2 + m1->y3*m2->y2 + m1->z3*m2->z2; + res->z3 = m1->x3*m2->x3 + m1->y3*m2->y3 + m1->z3*m2->z3; +} + +inline void DMatTDMatMult(DMatrix* m1, DMatrix* m2, DMatrix* res) { + res->x1 = m1->x1*m2->x1 + m1->y1*m2->y1 + m1->z1*m2->z1; + res->x2 = m1->x1*m2->x2 + m1->y1*m2->y2 + m1->z1*m2->z2; + res->x3 = m1->x1*m2->x3 + m1->y1*m2->y3 + m1->z1*m2->z3; + + res->y1 = m1->x2*m2->x1 + m1->y2*m2->y1 + m1->z2*m2->z1; + res->y2 = m1->x2*m2->x2 + m1->y2*m2->y2 + m1->z2*m2->z2; + res->y3 = m1->x2*m2->x3 + m1->y2*m2->y3 + m1->z2*m2->z3; + + res->z1 = m1->x3*m2->x1 + m1->y3*m2->y1 + m1->z3*m2->z1; + res->z2 = m1->x3*m2->x2 + m1->y3*m2->y2 + m1->z3*m2->z2; + res->z3 = m1->x3*m2->x3 + m1->y3*m2->y3 + m1->z3*m2->z3; +} + + +inline void MatVecMult(Matrix* m1, Vector* v1, Vector* res) { + res->x = m1->x1*v1->x + m1->x2*v1->y + m1->x3*v1->z; + res->y = m1->y1*v1->x + m1->y2*v1->y + m1->y3*v1->z; + res->z = m1->z1*v1->x + m1->z2*v1->y + m1->z3*v1->z; +} + +inline void MatDVecMult(Matrix* m1, DVector* v1, DVector* res) { + res->x = m1->x1*v1->x + m1->x2*v1->y + m1->x3*v1->z; + res->y = m1->y1*v1->x + m1->y2*v1->y + m1->y3*v1->z; + res->z = m1->z1*v1->x + m1->z2*v1->y + m1->z3*v1->z; +} + +inline void DMatVecMult(DMatrix* m1, Vector* v1, DVector* res) { + res->x = m1->x1*v1->x + m1->x2*v1->y + m1->x3*v1->z; + res->y = m1->y1*v1->x + m1->y2*v1->y + m1->y3*v1->z; + res->z = m1->z1*v1->x + m1->z2*v1->y + m1->z3*v1->z; +} + +inline void DMatVecMult(DMatrix* m1, Vector* v1, Vector* res) { + res->x = (float)(m1->x1*v1->x + m1->x2*v1->y + m1->x3*v1->z); + res->y = (float)(m1->y1*v1->x + m1->y2*v1->y + m1->y3*v1->z); + res->z = (float)(m1->z1*v1->x + m1->z2*v1->y + m1->z3*v1->z); +} + +inline void DMatDVecMult(DMatrix* m1, DVector* v1, DVector* res) { + res->x = m1->x1*v1->x + m1->x2*v1->y + m1->x3*v1->z; + res->y = m1->y1*v1->x + m1->y2*v1->y + m1->y3*v1->z; + res->z = m1->z1*v1->x + m1->z2*v1->y + m1->z3*v1->z; +} + +inline void MatTVecMult(Matrix* m1, Vector* v1, Vector* res) { + res->x = m1->x1*v1->x + m1->y1*v1->y + m1->z1*v1->z; + res->y = m1->x2*v1->x + m1->y2*v1->y + m1->z2*v1->z; + res->z = m1->x3*v1->x + m1->y3*v1->y + m1->z3*v1->z; +} + +inline void MatTDVecMult(Matrix* m1, DVector* v1, DVector* res) { + res->x = m1->x1*v1->x + m1->y1*v1->y + m1->z1*v1->z; + res->y = m1->x2*v1->x + m1->y2*v1->y + m1->z2*v1->z; + res->z = m1->x3*v1->x + m1->y3*v1->y + m1->z3*v1->z; +} + +inline void DMatTDVecMult(DMatrix* m1, DVector* v1, DVector* res) { + res->x = m1->x1*v1->x + m1->y1*v1->y + m1->z1*v1->z; + res->y = m1->x2*v1->x + m1->y2*v1->y + m1->z2*v1->z; + res->z = m1->x3*v1->x + m1->y3*v1->y + m1->z3*v1->z; +} + +inline void VecMul(Vector* v1, double m, Vector* res) { + res->x = (float)(v1->x * m); + res->y = (float)(v1->y * m); + res->z = (float)(v1->z * m); +} + +inline void VecMul(DVector* v1, double m, Vector* res) { + res->x = (float)(v1->x * m); + res->y = (float)(v1->y * m); + res->z = (float)(v1->z * m); +} + +inline void VecMul(DVector* v1, double m, DVector* res) { + res->x = v1->x * m; + res->y = v1->y * m; + res->z = v1->z * m; +} + +inline void VecMul(Vector* v1, double m, DVector* res) { + res->x = v1->x * m; + res->y = v1->y * m; + res->z = v1->z * m; +} + +inline void VecInv(Vector* v1, Vector* res) { + res->x = -v1->x; + res->y = -v1->y; + res->z = -v1->z; +} + +inline void VecInv(DVector* v1, DVector* res) { + res->x = -v1->x; + res->y = -v1->y; + res->z = -v1->z; +} + +inline void VecSub(Vector* v1, Vector* v2, Vector* res) { + res->x = v1->x - v2->x; + res->y = v1->y - v2->y; + res->z = v1->z - v2->z; +} + +inline void VecSub(DVector* v1, DVector* v2, DVector* res) { + res->x = v1->x - v2->x; + res->y = v1->y - v2->y; + res->z = v1->z - v2->z; +} + +inline void VecSub(DVector* v1, DVector* v2, Vector* res) { + res->x = (float)(v1->x - v2->x); + res->y = (float)(v1->y - v2->y); + res->z = (float)(v1->z - v2->z); +} + +inline void VecAdd(DVector* v1, DVector* v2, Vector* res) { + res->x = (float)(v1->x + v2->x); + res->y = (float)(v1->y + v2->y); + res->z = (float)(v1->z + v2->z); +} + +inline void VecAdd(DVector* v1, Vector* v2, DVector* res) { + res->x = v1->x + v2->x; + res->y = v1->y + v2->y; + res->z = v1->z + v2->z; +} + +inline void VecAdd(Vector* v1, Vector* v2, Vector* res) { + res->x = v1->x + v2->x; + res->y = v1->y + v2->y; + res->z = v1->z + v2->z; +} + +inline void VecAdd(Vector* v1, DVector* v2, Vector* res) { + res->x = (float)(v1->x + v2->x); + res->y = (float)(v1->y + v2->y); + res->z = (float)(v1->z + v2->z); +} + +inline void VecAdd(DVector* v1, DVector* v2, DVector* res) { + res->x = v1->x + v2->x; + res->y = v1->y + v2->y; + res->z = v1->z + v2->z; +} + +inline float VecDot(Vector* v1, Vector* v2) { + return(v1->x*v2->x + v1->y*v2->y + v1->z*v2->z); +} + +inline double VecDot(DVector* v1, DVector* v2) { + return(v1->x*v2->x + v1->y*v2->y + v1->z*v2->z); +} + +inline double VecDot(DVector* v1, Vector* v2) { + return(v1->x*v2->x + v1->y*v2->y + v1->z*v2->z); +} + +inline float VecDot(Vector* v) { + return(v->x*v->x + v->y*v->y + v->z*v->z); +} + +inline double VecDot(DVector* v) { + return(v->x*v->x + v->y*v->y + v->z*v->z); +} + +inline float VecMag(Vector* v1) { + return(float) sqrt(VecDot(v1, v1)); +} + +inline double VecMag(DVector* v1) { + return sqrt(VecDot(v1, v1)); +} + +inline void VecCross(Vector* v1, Vector* v2, Vector* res) { + res->x = v1->y*v2->z - v1->z*v2->y; + res->y = v1->z*v2->x - v1->x*v2->z; + res->z = v1->x*v2->y - v1->y*v2->x; +} + +inline void VecCross(DVector* v1, DVector* v2, DVector* res) { + res->x = v1->y*v2->z - v1->z*v2->y; + res->y = v1->z*v2->x - v1->x*v2->z; + res->z = v1->x*v2->y - v1->y*v2->x; +} + +inline int VecNorm(Vector* v1, Vector* res) { + float temp = VecDot(v1, v1); + if(temp == 0.0f) { *res = zero_vector; return 0; } + temp = 1.0f / float(sqrt(temp)); + + res->x = v1->x * temp; + res->y = v1->y * temp; + res->z = v1->z * temp; + return 1; +} + +inline int VecNorm(DVector* v1, DVector* res) { + double temp = VecDot(v1, v1); + if(temp == 0.0) { *res = zero_dvector; return 0; } + temp = 1.0 / sqrt(temp); + + res->x = v1->x * temp; + res->y = v1->y * temp; + res->z = v1->z * temp; + return 1; +} + +inline void VecMax(Vector* in, Vector* max, Vector* res) { + if(in->x < max->x) res->x = max->x; else res->x = in->x; + if(in->y < max->y) res->y = max->y; else res->y = in->y; + if(in->z < max->z) res->z = max->z; else res->z = in->z; +} + +inline void VecMin(Vector* in, Vector* min, Vector* res) { + if(in->x > min->x) res->x = min->x; else res->x = in->x; + if(in->y > min->y) res->y = min->y; else res->y = in->y; + if(in->z > min->z) res->z = min->z; else res->z = in->z; +} + +inline void VecClip(Vector* in, Vector* max, Vector* min, Vector* res) { + if(in->x > max->x) res->x = max->x; + else if(in->x < min->x) res->x = min->x; else res->x = in->x; + if(in->y > max->y) res->y = max->y; + else if(in->y < min->y) res->y = min->y; else res->y = in->y; + if(in->z > max->z) res->z = max->z; + else if(in->z < min->z) res->z = min->z; else res->z = in->z; +} + +/* Obeys RH rule p2-p1-p3 */ +inline int FindNormal(Vector* p1, Vector* p2, Vector* p3, Vector* res) { + res->x = (p2->y-p1->y) * (p3->z-p1->z) - (p2->z-p1->z) * (p3->y-p1->y); + res->y = (p2->z-p1->z) * (p3->x-p1->x) - (p2->x-p1->x) * (p3->z-p1->z); + res->z = (p2->x-p1->x) * (p3->y-p1->y) - (p2->y-p1->y) * (p3->x-p1->x); + + return VecNorm(res, res); +} + +inline int FindNormal(DVector* p1, DVector* p2, DVector* p3, DVector* res) { + res->x = (p2->y-p1->y) * (p3->z-p1->z) - (p2->z-p1->z) * (p3->y-p1->y); + res->y = (p2->z-p1->z) * (p3->x-p1->x) - (p2->x-p1->x) * (p3->z-p1->z); + res->z = (p2->x-p1->x) * (p3->y-p1->y) - (p2->y-p1->y) * (p3->x-p1->x); + + return VecNorm(res, res); +} + +inline int FindNormal(Vector* p1, Vector* p2, Vector* p3, DVector* res) { + res->x = ((double)p2->y-p1->y) * ((double)p3->z-p1->z); + res->x -= ((double)p2->z-p1->z) * ((double)p3->y-p1->y); + res->y = ((double)p2->z-p1->z) * ((double)p3->x-p1->x); + res->y -= ((double)p2->x-p1->x) * ((double)p3->z-p1->z); + res->z = ((double)p2->x-p1->x) * ((double)p3->y-p1->y); + res->z -= ((double)p2->y-p1->y) * ((double)p3->x-p1->x); + + return VecNorm(res, res); +} + +inline void BuildMatrix(float xr, float yr, float zr, Matrix* m1) { + double sx = sin(xr), cx = cos(xr); + double sy = sin(yr), cy = cos(yr); + double sz = sin(zr), cz = cos(zr); + + m1->x1 = float(cz*cy + sz*sx*sy); + m1->x2 = float(sz*cx); + m1->x3 = float(-cz*sy + sz*sx*cy); + m1->y1 = float(-sz*cy + cz*sx*sy); + m1->y2 = float(cz*cx); + m1->y3 = float(sz*sy + cz*sx*cy); + m1->z1 = float(cx*sy); + m1->z2 = float(-sx); + m1->z3 = float(cx*cy); +} + +inline void BuildMatrix(double xr, double yr, double zr, DMatrix* m1) { + double sx = sin(xr), cx = cos(xr); + double sy = sin(yr), cy = cos(yr); + double sz = sin(zr), cz = cos(zr); + + m1->x1 = cz*cy + sz*sx*sy; + m1->x2 = sz*cx; + m1->x3 = -cz*sy + sz*sx*cy; + m1->y1 = -sz*cy + cz*sx*sy; + m1->y2 = cz*cx; + m1->y3 = sz*sy + cz*sx*cy; + m1->z1 = cx*sy; + m1->z2 = -sx; + m1->z3 = cx*cy; +} + +inline void MakeVecRotMatrix(Vector* v, Matrix* m) { + float r, div; + if((r = VecDot(v, v)) < 1.0e-20f) { + *m = identity_matrix; + return; + } + r = float(sqrt(r)); + div = 1 / r; + + Vector n; + n.x = v->x * div; + n.y = v->y * div; + n.z = v->z * div; + + float cr = cosf(r); + float cri = 1.0f - cr; + float sr = sinf(r); + + m->x1 = (n.x * n.x) * cri + cr; + m->x2 = (n.x * n.y) * cri - (n.z * sr); + m->x3 = (n.x * n.z) * cri + (n.y * sr); + + m->y1 = (n.y * n.x) * cri + (n.z * sr); + m->y2 = (n.y * n.y) * cri + cr ; + m->y3 = (n.y * n.z) * cri - (n.x * sr); + + m->z1 = (n.z * n.x) * cri - (n.y * sr); + m->z2 = (n.z * n.y) * cri + (n.x * sr); + m->z3 = (n.z * n.z) * cri + cr; +} + +inline void MakeVecRotDMatrix(DVector* v, DMatrix* m) { + double r, div; + if ((r = VecDot(v, v)) < 1.0e-20f) { + *m = identity_dmatrix; + return; + } + r = sqrt(r); + div = 1 / r; + + DVector n; + n.x = v->x * div; + n.y = v->y * div; + n.z = v->z * div; + + double cr = cos(r); + double cri = 1.0 - cr; + double sr = sin(r); + + m->x1 = (n.x * n.x) * cri + cr; + m->x2 = (n.x * n.y) * cri - (n.z * sr); + m->x3 = (n.x * n.z) * cri + (n.y * sr); + + m->y1 = (n.y * n.x) * cri + (n.z * sr); + m->y2 = (n.y * n.y) * cri + cr ; + m->y3 = (n.y * n.z) * cri - (n.x * sr); + + m->z1 = (n.z * n.x) * cri - (n.y * sr); + m->z2 = (n.z * n.y) * cri + (n.x * sr); + m->z3 = (n.z * n.z) * cri + cr; +} + diff --git a/src/sbre/models.cpp b/src/sbre/models.cpp new file mode 100644 index 0000000..de76567 --- /dev/null +++ b/src/sbre/models.cpp @@ -0,0 +1,1261 @@ +#include "sbre_int.h" +#include "sbre_anim.h" + +const int SUB_WING2 = 1; +const int SUB_DISH = 2; +const int SUB_NOSEWHEEL = 3; +const int SUB_WING = 4; +const int SUB_NACELLE = 5; +const int SUB_NWUNIT = 6; +const int SUB_MAINWHEEL = 7; +const int SUB_MWUNIT = 8; + +enum AxisIndex { + A_X = 0, A_Y, A_Z, A_NX, A_NY, A_NZ, +}; + +static PlainVertex tetravtx1[] = { + { VTYPE_PLAIN, { 0.0f, 50.0f, 0.0f } }, /* 6. */ + { VTYPE_PLAIN, { -50.0f, -30.0f, 30.0f } }, + { VTYPE_PLAIN, { 50.0f, -30.0f, 30.0f } }, + { VTYPE_PLAIN, { 0.0f, -30.0f, -50.0f } }, + { VTYPE_PLAIN, { 0.0f, -30.0f, 0.0f } }, /* 10, wheel base. */ +}; + +static CompoundVertex tetravtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1), static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 tetradata[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_TRIFLAT, 6, 7, 8, + PTYPE_TRIFLAT, 6, 8, 9, + PTYPE_TRIFLAT, 6, 9, 7, + PTYPE_TRIFLAT, 9, 8, 7, + PTYPE_SUBOBJECT, 0x8000, SUB_NOSEWHEEL, 10, 0, 4, 100, + PTYPE_END, +}; + +static Model tetramodel = { 1.0f, 11, tetravtx1, 20, 0, tetravtx2, + 0, 0, 0, 0, tetradata, 0 }; + + +static PlainVertex circlevtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, +}; + +static CompoundVertex circlevtx2[] = { + { VTYPE_NORM, { 6, 7, 8, static_cast(-1), static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 circledata[] = { + PTYPE_MATANIM, AFUNC_THRUSTPULSE, + 0, 0, 0, 0, 0, 0, 100, 50, 50, 100, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 50, + PTYPE_CIRCLE, 0, 12, 6, 5, 1, 2000, + PTYPE_END, +}; + +static Model circlemodel = { 1.0f, 7, circlevtx1, 20, 0, circlevtx2, + 0, 0, 0, 0, circledata, 1 }; + + +static PlainVertex cylvtx1[] = { + { VTYPE_PLAIN, { -100.0f, 20.0f, 0.0f } }, + { VTYPE_PLAIN, { 100.0f, -10.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, +}; + +static CompoundVertex cylvtx2[] = { + { VTYPE_NORM, { 6, 7, 8, static_cast(-1), static_cast(-1) } }, +}; + +static uint16 cyldata[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + // PTYPE_CYLINDER, 0, 8, 6, 7, 20, 2000, + PTYPE_TUBE, 0, 8, 6, 7, 20, 2000, 1000, + PTYPE_END, +}; + +static Model cylmodel = { 1.0f, 9, cylvtx1, 20, 1, cylvtx2, + 0, 0, 0, 0, cyldata, 1 }; + + +static PlainVertex nwunitvtx1[] = { + { VTYPE_PLAIN, { 1.5f, 0.0f, 6.0f } }, /* 6 flap. */ + { VTYPE_PLAIN, { 1.5f, 0.0f, -1.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 6.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -1.0f } }, + { VTYPE_PLAIN, { 1.5f, 1.5f, 6.0f } }, + { VTYPE_PLAIN, { 1.5f, 1.5f, -1.0f } }, + + { VTYPE_PLAIN, { 0.0f, 1.5f, 0.0f } }, /* 12, tangents. */ + { VTYPE_PLAIN, { 1.5f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, /* 14, wheel pos. */ +}; + +static CompoundVertex nwunitvtx2[] = { + { VTYPE_ANIMHERM, { 8, 10, 12, 13, AFUNC_GFLAP } }, /* 20, flap paths. */ + { VTYPE_ANIMHERM, { 9, 11, 12, 13, AFUNC_GFLAP } }, + { VTYPE_ANIMLIN, { 2, 1, static_cast(-1), static_cast(-1), AFUNC_GEAR } }, /* Gear y axis. */ +}; + +static uint16 nwunitdata[] = { + PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT | RFLAG_XREF, 8, 6, 7, 9, /* Flap internal. */ + + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT | RFLAG_XREF, 6, 20, 21, 7, /* Flaps. */ + PTYPE_QUADFLAT | RFLAG_XREF, 6, 7, 21, 20, + + // PTYPE_CYLINDER, 3, 8, 6, 7, 0, 1000, + + PTYPE_SUBOBJECT, 0x8000, SUB_NOSEWHEEL, 14, 22, 2, 100, + + PTYPE_END, +}; + +static Model nwunitmodel = { 1.0f, 15, nwunitvtx1, 20, 3, nwunitvtx2, + 0, 0, 0, 0, nwunitdata, 0 }; + + +static PlainVertex nosewheelvtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, /* 6, strut. */ + { VTYPE_PLAIN, { 0.0f, 3.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 5.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.5f, 5.0f, 0.0f } }, /* 9, wheel. */ + { VTYPE_PLAIN, { 1.0f, 5.0f, 0.0f } }, +}; + +static CompoundVertex nosewheelvtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1), static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 nosewheeldata[] = { + PTYPE_MATFIXED, 50, 50, 50, 100, 100, 100, 200, 0, 0, 0, + PTYPE_CYLINDER, 0, 8, 6, 8, 2, 40, + PTYPE_CYLINDER, 1, 8, 7, 8, 2, 50, + PTYPE_MATFIXED, 30, 30, 30, 0, 0, 0, 100, 0, 0, 0, + PTYPE_CYLINDER | RFLAG_XREF, 2, 8, 9, 10, 2, 100, + PTYPE_END, +}; + +static Model nosewheelmodel = { 1.0f, 11, nosewheelvtx1, 20, 0, nosewheelvtx2, + 0, 0, 0, 0, nosewheeldata, 4 }; + + +static PlainVertex mwunitvtx1[] = { + { VTYPE_PLAIN, { 1.5f, 0.0f, 6.0f } }, /* 6, flap. */ + { VTYPE_PLAIN, { 1.5f, 0.0f, -1.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 6.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -1.0f } }, + { VTYPE_PLAIN, { 1.5f, 1.5f, 6.0f } }, + { VTYPE_PLAIN, { 1.5f, 1.5f, -1.0f } }, + + { VTYPE_PLAIN, { 0.0f, 1.5f, 0.0f } }, /* 12, tangents. */ + { VTYPE_PLAIN, { 1.5f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, /* 14, wheel pos. */ +}; + +static CompoundVertex mwunitvtx2[] = { + { VTYPE_ANIMHERM, { 8, 10, 12, 13, AFUNC_GFLAP } }, /* 20, flap paths. */ + { VTYPE_ANIMHERM, { 9, 11, 12, 13, AFUNC_GFLAP } }, + { VTYPE_ANIMLIN, { 2, 1, static_cast(-1), static_cast(-1), AFUNC_GEAR } }, /* Gear y axis. */ +}; + +static uint16 mwunitdata[] = { + PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT | RFLAG_XREF, 8, 6, 7, 9, /* Flap internal. */ + + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT | RFLAG_XREF, 6, 20, 21, 7, /* Flaps. */ + PTYPE_QUADFLAT | RFLAG_XREF, 6, 7, 21, 20, + + // PTYPE_CYLINDER, 3, 8, 6, 7, 0, 1000, + + PTYPE_SUBOBJECT, 0x8000, SUB_MAINWHEEL, 14, 22, 2, 100, + + PTYPE_END, +}; + +static Model mwunitmodel = { 1.0f, 15, mwunitvtx1, 20, 3, mwunitvtx2, + 0, 0, 0, 0, mwunitdata, 0 }; + + +static PlainVertex mainwheelvtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, /* 6, strut. */ + { VTYPE_PLAIN, { 0.0f, 3.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 5.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.5f, 5.0f, 1.1f } }, /* 9, wheel 1. */ + { VTYPE_PLAIN, { 1.0f, 5.0f, 1.1f } }, + { VTYPE_PLAIN, { 0.5f, 5.0f, -1.1f } }, /* 11, wheel 2. */ + { VTYPE_PLAIN, { 1.0f, 5.0f, -1.1f } }, + { VTYPE_PLAIN, { 0.0f, 5.0f, 1.4f } }, /* 13, crossbar. */ + { VTYPE_PLAIN, { 0.0f, 5.0f, -1.4f } }, +}; + +static CompoundVertex mainwheelvtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1), static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 mainwheeldata[] = { + PTYPE_MATFIXED, 50, 50, 50, 100, 100, 100, 200, 0, 0, 0, + PTYPE_CYLINDER, 0, 8, 6, 8, 2, 40, + PTYPE_CYLINDER, 1, 8, 7, 8, 2, 50, + PTYPE_CYLINDER, 4, 4, 13, 14, 0, 50, + PTYPE_MATFIXED, 30, 30, 30, 0, 0, 0, 100, 0, 0, 0, + PTYPE_CYLINDER | RFLAG_XREF, 2, 8, 9, 10, 2, 100, + PTYPE_CYLINDER | RFLAG_XREF, 3, 8, 11, 12, 2, 100, + PTYPE_END, +}; + +static Model mainwheelmodel = { 1.0f, 15, mainwheelvtx1, 20, 0, mainwheelvtx2, + 0, 0, 0, 0, mainwheeldata, 5 }; + +static PlainVertex nacellevtx1[] = { + { VTYPE_PLAIN, { 30.0f, 0.0f, 30.0f } }, /* 6 */ + { VTYPE_PLAIN, { 30.0f, 0.0f, -30.0f } }, + { VTYPE_PLAIN, { 30.0f, 10.0f, 0.0f } }, + { VTYPE_PLAIN, { 40.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 30.0f, -10.0f, 0.0f } }, + { VTYPE_PLAIN, { 20.0f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 14.0f, 0.0f, 0.0f } }, /* 12, tangents. */ + { VTYPE_PLAIN, { -14.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 14.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, -14.0f, 0.0f } }, +}; + +static CompoundVertex nacellevtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1), static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 nacelledata[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_COMPSMOOTH | RFLAG_XREF, 0, 5, 6, 2, 8, 1, + COMP_HERMITE, 11, 3, 13, 15, + COMP_HERMITE, 10, 4, 15, 12, + COMP_HERMITE, 9, 0, 12, 14, + COMP_HERMITE, 8, 1, 14, 13, + COMP_END, + PTYPE_COMPSMOOTH | RFLAG_XREF, 1, 5, 7, 5, 8, 1, + COMP_HERMITE, 9, 0, 12, 15, + COMP_HERMITE, 10, 4, 15, 13, + COMP_HERMITE, 11, 3, 13, 14, + COMP_HERMITE, 8, 1, 14, 12, + COMP_END, + PTYPE_END, +}; + +static Model nacellemodel = { 1.0f, 16, nacellevtx1, 20, 0, nacellevtx2, + 0, 0, 0, 0, nacelledata, 2 }; + + +/* Do wings as subobjects. */ +static PlainVertex shipvtx1[] = { + { VTYPE_PLAIN, { 5.0f, 10.0f, 30.0f } }, /* 6, top four body verts. */ + { VTYPE_PLAIN, { -5.0f, 10.0f, 30.0f } }, + { VTYPE_PLAIN, { 5.0f, 10.0f, -30.0f } }, + { VTYPE_PLAIN, { -5.0f, 10.0f, -30.0f } }, + + { VTYPE_PLAIN, { 11.16025f, -0.6698729f, 25.0f } }, /* 10, right four body verts. */ + { VTYPE_PLAIN, { 6.160254f, -9.330127f, 35.0f } }, + { VTYPE_PLAIN, { 11.16025f, -0.6698729f, -35.0f } }, + { VTYPE_PLAIN, { 6.160254f, -9.330127f, -30.0f } }, + + { VTYPE_PLAIN, { -11.16025f, -0.6698729f, 25.0f } }, /* 14, left four body verts. */ + { VTYPE_PLAIN, { -6.160254f, -9.330127f, 35.0f } }, + { VTYPE_PLAIN, { -11.16025f, -0.6698729f, -35.0f } }, + { VTYPE_PLAIN, { -6.160254f, -9.330127f, -30.0f } }, + + { VTYPE_PLAIN, { 5.0f, -0.6698729f, 60.0f } }, /* 18, front two verts. */ + { VTYPE_PLAIN, { -5.0f, -0.6698729f, 60.0f } }, + + { VTYPE_PLAIN, { 0.0f, 10.0f, 0.0f } }, /* 20, top wing. */ + { VTYPE_PLAIN, { 1.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 1.0f, 0.0f } }, + + { VTYPE_PLAIN, { 8.660254f, -5.0f, 0.0f } }, /* 23, right wing. */ + { VTYPE_PLAIN, { -0.5f, -0.8660254f, 0.0f } }, + { VTYPE_PLAIN, { 0.8660254f, -0.5f, 0.0f } }, + + { VTYPE_PLAIN, { -8.660254f, -5.0f, 0.0f } }, /* 26, left wing. */ + { VTYPE_PLAIN, { -0.5f, 0.8660254f, 0.0f } }, + { VTYPE_PLAIN, { -0.8660254f, -0.5f, 0.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, -40.0f } }, /* 29, main thruster. */ + { VTYPE_PLAIN, { 11.0f, 0.0f, 35.0f } }, /* 30, retro. */ + { VTYPE_PLAIN, { -11.0f, 0.0f, 35.0f } }, + { VTYPE_PLAIN, { 9.0f, 5.0f, 30.0f } }, /* 32, right. */ + { VTYPE_PLAIN, { 12.0f, -5.0f, -30.0f } }, + { VTYPE_PLAIN, { -12.0f, -5.0f, 30.0f } }, /* 34, left. */ + { VTYPE_PLAIN, { -9.0f, 5.0f, -30.0f } }, + { VTYPE_PLAIN, { 0.0f, 12.0f, 30.0f } }, /* 36, top. */ + { VTYPE_PLAIN, { 0.0f, 12.0f, -30.0f } }, + { VTYPE_PLAIN, { 0.0f, -12.0f, 30.0f } }, /* 38, bottom. */ + { VTYPE_PLAIN, { 0.0f, -12.0f, -30.0f } }, + + { VTYPE_PLAIN, { 0.0f, -9.330127f, 30.0f } }, /* 40, nosewheel. */ + { VTYPE_PLAIN, { 0.0f, -9.330127f, -13.0f } }, /* 41, mainwheel. */ + +}; + +static CompoundVertex shipvtx2[] = { + { VTYPE_ANIMLIN, { 25, 0, static_cast(-1), static_cast(-1), 0 } }, /* 50, right wing yaxis. */ + { VTYPE_CROSS, { 50, 2, static_cast(-1), static_cast(-1), 0 } }, /* Right wing xaxis. */ + + { VTYPE_ANIMLIN, { 28, 3, static_cast(-1), static_cast(-1), 0 } }, /* 52, left wing yaxis. */ + { VTYPE_CROSS, { 52, 2, static_cast(-1), static_cast(-1), static_cast(-1) } }, /* Right wing xaxis. */ + + { VTYPE_NORM, { 16, 14, 7, static_cast(-1), static_cast(-1) } }, /* 54, left text normal. */ + { VTYPE_NORM, { 12, 8, 6, static_cast(-1), static_cast(-1) } }, /* 55, right text normal. */ + +}; + +static uint16 shipdata[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT, 7, 6, 8, 9, /* Top. */ + PTYPE_QUADFLAT, 13, 11, 15, 17, /* Bottom. */ + PTYPE_QUADFLAT | RFLAG_XREF, 8, 6, 10, 12, /* Side top. */ + PTYPE_QUADFLAT | RFLAG_XREF, 12, 10, 11, 13, /* Side bottom. */ + PTYPE_QUADFLAT, 9, 8, 12, 16, /* Back top. */ + PTYPE_QUADFLAT, 16, 12, 13, 17, /* Back bottom. */ + + PTYPE_QUADFLAT, 6, 7, 19, 18, /* Front top. */ + PTYPE_QUADFLAT, 18, 19, 15, 11, /* Front bottom. */ + PTYPE_TRIFLAT | RFLAG_XREF, 6, 18, 10, /* Front side top. */ + PTYPE_TRIFLAT | RFLAG_XREF, 10, 18, 11, /* Front side bottom. */ + + PTYPE_SUBOBJECT, 0x8000, SUB_WING, 20, 22, 2, 100, + PTYPE_SUBOBJECT, 0x8000, SUB_WING, 23, 50, 2, 100, + PTYPE_SUBOBJECT, 0x8000, SUB_WING, 26, 52, 2, 100, + + PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_ZBIAS, 54, 5, + PTYPE_TEXT, 0, 0x8000, 14, 54, 5, 500, 200, 1000, + PTYPE_ZBIAS, 55, 5, + PTYPE_TEXT, 0, 0x8000, 12, 55, 2, 1100, 200, 1000, + + PTYPE_ZBIAS, 4, 5, + PTYPE_SUBOBJECT, 0, SUB_NWUNIT, 40, 4, 5, 200, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 41, 4, 5, 200, + + // PTYPE_TEXT, -1, -1, 12, 0, 1, 5000, + PTYPE_ZBIAS, 0x8000, 5, + + PTYPE_END, +}; + +static Thruster shipthruster[] = { + { 29, 5 | THRUST_NOANG, 50.0f }, + { 30, 2 | THRUST_NOANG, 35.0f }, /* Retros. */ + { 31, 2 | THRUST_NOANG, 35.0f }, + { 32, 0, 25.0f }, { 33, 0, 25.0f }, /* Right. */ + { 34, 3, 25.0f }, { 35, 3, 25.0f }, /* Left. */ + { 36, 1, 25.0f }, { 37, 1, 25.0f }, /* Top. */ + { 38, 4, 25.0f }, { 39, 4, 25.0f }, /* Bottom. */ +}; + +static Model shipmodel = { 1.0f, 42, shipvtx1, 50, 6, shipvtx2, + 0, 0, 11, shipthruster, shipdata, 0 }; + + +static PlainVertex wingvtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 1.0f } }, /* 6, bottom front. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -1.0f } }, /* Bottom back. */ + { VTYPE_PLAIN, { 0.0f, 1.5f, 0.0f } }, /* Top front. */ + { VTYPE_PLAIN, { 0.0f, 1.5f, -1.5f } }, /* Top back. */ + + { VTYPE_PLAIN, { 0.1f, 0.75f, -0.5f } }, /* 10, sidecentre. */ + { VTYPE_PLAIN, { 0.0f, 1.5f, -0.75f } }, /* Topcentre. */ + + { VTYPE_PLAIN, { 1.0f, 0.0f, 0.0f } }, /* 12, norm, sidecentre. */ + { VTYPE_PLAIN, { 0.0f, 1.0f, 0.0f } }, /* norm, topcentre. */ + + { VTYPE_PLAIN, { 0.4f, 0.0f, -2.0f } }, /* 14, tan 0->1, 0. */ + { VTYPE_PLAIN, { -0.4f, 0.0f, -2.0f } }, /* tan 0->1, 1. */ + { VTYPE_PLAIN, { 0.0f, 1.5f, -0.5f } }, /* 16, tan 1->3, 0, 1. */ + { VTYPE_PLAIN, { 0.4f, 0.0f, 1.5f } }, /* 17, tan 3->2, 0. */ + { VTYPE_PLAIN, { -0.4f, 0.0f, 1.5f } }, /* tan 3->2, 1. */ + { VTYPE_PLAIN, { 0.0f, -1.5f, 1.0f } }, /* 19, tan 2->0, 0, 1. */ + + { VTYPE_PLAIN, { 0.4f, 0.0f, -1.5f } }, /* 20, tan 2->3 top, 0. */ + { VTYPE_PLAIN, { -0.4f, 0.0f, -1.5f } }, /* tan 2->3 top, 1. */ + { VTYPE_PLAIN, { -0.4f, 0.0f, 1.5f } }, /* 22, tan 3->2 top, 0. */ + { VTYPE_PLAIN, { 0.4f, 0.0f, 1.5f } }, /* tan 3->2 top, 1. */ +}; + +static CompoundVertex wingvtx2[] = { + { VTYPE_CROSS, { 19, 14, static_cast(-1),static_cast(-1),static_cast(-1), } }, /* 30, norm 0. */ + { VTYPE_CROSS, { 15, 16, static_cast(-1),static_cast(-1),static_cast(-1), } }, /* norm 1. */ + { VTYPE_CROSS, { 16, 17, static_cast(-1),static_cast(-1),static_cast(-1), } }, /* norm 3. */ + { VTYPE_CROSS, { 18, 19, static_cast(-1),static_cast(-1),static_cast(-1), } }, /* norm 2. */ +}; + +static uint16 wingdata[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_COMPSMOOTH | RFLAG_XREF, 0, 5, 10, 12, 6, 30, /* Side. */ + COMP_HERMITE, 7, 31, 14, 15, + COMP_HERMITE, 9, 32, 16, 16, + COMP_HERMITE, 8, 33, 17, 18, + COMP_HERMITE, 6, 30, 19, 19, + COMP_END, + PTYPE_COMPSMOOTH, 1, 5, 11, 13, 8, 13, /* Top. */ + COMP_HERMITE, 9, 13, 20, 21, + COMP_HERMITE, 8, 13, 22, 23, + COMP_END, + PTYPE_END, +}; + +static Model wingmodel = { 25.0f, 24, wingvtx1, 30, 4, wingvtx2, + 0, 0, 0, 0, wingdata, 2 }; + +static PlainVertex ship2vtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 35.0f } }, /* 6, nose point. */ + { VTYPE_DIR, { 0.0f, 1.0f, 0.2f } }, /* nose normal. */ + { VTYPE_PLAIN, { 6.0f, 0.0f, 18.0f } }, /* 8, r edge forward mid. */ + { VTYPE_DIR, { 0.2f, 1.0f, 0.1f } }, /* norm. */ + { VTYPE_PLAIN, { 12.0f, 0.0f, -2.0f } }, /* 10, r edge back mid. */ + { VTYPE_DIR, { 0.2f, 1.0f, 0.1f } }, /* norm. */ + { VTYPE_PLAIN, { 7.5f, 0.0f, -25.0f } }, /* 12, r edge back. */ + { VTYPE_DIR, { 0.0f, 1.0f, -0.2f } }, /* norm. */ + + { VTYPE_PLAIN, { 0.0f, 3.0f, 15.0f } }, /* 14, cockpit front. */ + { VTYPE_DIR, { 0.0f, 1.0f, -0.08f } }, /* norm. */ + { VTYPE_PLAIN, { 1.5f, 3.0f, 13.5f } }, /* 16, cockpit right. */ + { VTYPE_DIR, { 0.0f, 1.0f, -0.08f } }, /* norm. */ + { VTYPE_PLAIN, { 0.0f, 3.0f, 10.0f } }, /* 18, cockpit back. */ + { VTYPE_DIR, { 0.0f, 1.0f, -0.08f } }, /* norm. */ + { VTYPE_PLAIN, { -1.5f, 3.0f, 13.5f } }, /* 20, cockpit left. */ + { VTYPE_DIR, { 0.0f, 1.0f, -0.08f } }, /* norm. */ + + { VTYPE_PLAIN, { 6.0f, 3.0f, -5.0f } }, /* 22, inner right. */ + { VTYPE_DIR, { 0.2f, 1.0f, 0.2f } }, /* norm. */ + { VTYPE_PLAIN, { 0.0f, 3.0f, -5.0f } }, /* 24, inner mid. */ + { VTYPE_DIR, { -0.2f, 1.0f, 0.2f } }, /* norm. */ + + { VTYPE_PLAIN, { 2.0f, 2.0f, 23.0f } }, /* 26, fwd midpoint. */ + { VTYPE_DIR, { 0.0f, 1.0f, 0.1f } }, /* norm. */ + { VTYPE_PLAIN, { 5.0f, 2.5f, 5.0f } }, /* 28, right midpoint. */ + { VTYPE_DIR, { 0.08f, 1.0f, 0.04f } }, /* norm. */ + { VTYPE_PLAIN, { 7.0f, 2.0f, -14.0f } }, /* 30, rear right midpoint. */ + { VTYPE_DIR, { 0.04f, 1.0f, -0.1f } }, /* norm. */ + + { VTYPE_PLAIN, { 3.0f, 3.0f, 5.0f } }, /* 32, central midpoint. */ + { VTYPE_PLAIN, { 0.0f, 4.0f, 12.5f } }, /* 33, cockpit midpoint. */ + { VTYPE_PLAIN, { 3.75f, 4.0f, -20.0f } }, /* 34, nacelle midpoint. */ + + { VTYPE_PLAIN, { 7.5f, 0.0f, -30.0f } }, /* 35, nacelle outer. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -30.0f } }, /* 36, nacelle inner. */ + + /* Edge tangents. */ + { VTYPE_PLAIN, { -6.0f, 4.0f, -3.0f } }, /* 37, edge to mid. */ + { VTYPE_PLAIN, { -6.0f, 0.0f, -3.0f } }, + { VTYPE_PLAIN, { 0.0f, 4.0f, 20.0f } }, /* 39, rear to mid. */ + { VTYPE_PLAIN, { -2.5f, 0.0f, 20.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, 20.0f } }, /* 41, mid to nose. */ + { VTYPE_PLAIN, { 0.0f, -4.0f, 20.0f } }, + { VTYPE_PLAIN, { 6.0f, 0.0f, 3.0f } }, /* 43, mid to edge. */ + { VTYPE_PLAIN, { 6.0f, -4.0f, 3.0f } }, + { VTYPE_PLAIN, { 2.5f, 0.0f, -20.0f } }, /* 45, mid to rear. */ + { VTYPE_PLAIN, { 0.0f, -4.0f, -20.0f } }, + + { VTYPE_PLAIN, { 1.5f, 0.0f, 0.0f } }, /* 47, cockpit CW tangents. */ + { VTYPE_PLAIN, { -1.5f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 1.5f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -1.5f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 3.5f } }, /* 51 */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -3.5f } }, + + { VTYPE_PLAIN, { 10.0f, 0.0f, -20.0f } }, /* 53, rear edge tangents. */ + { VTYPE_PLAIN, { -10.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { -10.0f, 0.0f, 20.0f } }, /* 55, CCW. */ + { VTYPE_PLAIN, { 10.0f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 0.0f, 5.0f, 0.0f } }, /* 57, nacelle tangents. */ + { VTYPE_PLAIN, { 0.0f, -5.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 12.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -12.0f } }, + + { VTYPE_PLAIN, { 3.75f, 4.0f, -30.0f } }, /* 61, nacelle rear midpoint. */ + { VTYPE_PLAIN, { 4.0f, 0.0f, 0.0f } }, /* And tangents. */ + { VTYPE_PLAIN, { -4.0f, 0.0f, 0.0f } }, + + /* Underside points. */ + { VTYPE_PLAIN, { 5.0f, 0.0f, 5.0f } }, /* 64, upper outer vent. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, 5.0f } }, /* 65, upper inner vent. */ + { VTYPE_PLAIN, { 5.0f, -2.0f, 3.0f } }, /* 66, lower outer vent. */ + { VTYPE_PLAIN, { 0.0f, -2.0f, 3.0f } }, /* 67, lower inner vent. */ + { VTYPE_PLAIN, { 5.0f, -2.0f, -30.0f } }, /* 68, nacelle outer underside. */ + { VTYPE_PLAIN, { 0.0f, -2.0f, -30.0f } }, /* 69, nacelle inner underside. */ + { VTYPE_PLAIN, { 13.0f, 0.0f, -14.0f } }, /* 70, rear underside centre. */ + { VTYPE_PLAIN, { 7.5f, 0.0f, 3.0f } }, /* 71, vent outer edge. */ + + { VTYPE_PLAIN, { 3.75f, 0.7f, -30.0f } }, /* 72, engine midpoint. */ + + { VTYPE_PLAIN, { 0.0f, 0.0f, 15.0f } }, /* 73, nose gear pos. */ + { VTYPE_PLAIN, { 3.75f, -2.0f, -15.0f } }, /* 74, rear right gear. */ + { VTYPE_PLAIN, { -3.75f, -2.0f, -15.0f } }, /* 75, rear left gear. */ + + { VTYPE_PLAIN, { 3.75f, 0.7f, -32.0f } }, /* 76, engine end. */ + + { VTYPE_PLAIN, { 4.5f, -0.3f, 4.7f } }, /* 77, retro vent. */ + { VTYPE_PLAIN, { 0.5f, -0.3f, 4.7f } }, + { VTYPE_PLAIN, { 4.5f, -1.7f, 3.3f } }, + { VTYPE_PLAIN, { 0.5f, -1.7f, 3.3f } }, + + /* Main & retro thrusters. */ + { VTYPE_PLAIN, { 3.75f, 0.7f, -32.0f } }, /* 81 */ + { VTYPE_PLAIN, { -3.75f, 0.7f, -32.0f } }, + { VTYPE_PLAIN, { 2.5f, -1.0f, 5.0f } }, + { VTYPE_PLAIN, { -2.5f, -1.0f, 5.0f } }, + + /* Vertical thrusters. */ + { VTYPE_PLAIN, { 9.0f, 1.5f, -10.0f } }, /* 85 */ + { VTYPE_PLAIN, { 9.0f, -0.5f, -10.0f } }, + { VTYPE_PLAIN, { -9.0f, 1.5f, -10.0f } }, + { VTYPE_PLAIN, { -9.0f, -0.5f, -10.0f } }, + { VTYPE_PLAIN, { 0.0f, 3.5f, 8.0f } }, + { VTYPE_PLAIN, { 0.0f, -0.5f, 25.0f } }, + + /* Horizontal thrusters. */ + { VTYPE_PLAIN, { 8.0f, 0.0f, -28.0f } }, /* 91 */ + { VTYPE_PLAIN, { -8.0f, 0.0f, -28.0f } }, + { VTYPE_PLAIN, { 3.5f, 0.0f, 25.0f } }, + { VTYPE_PLAIN, { -3.5f, 0.0f, 25.0f } }, + + /* Text norms. */ + { VTYPE_DIR, { 2.0f, -2.5f, 0.0f } }, /* 95 */ + { VTYPE_DIR, { -2.0f, -2.5f, 0.0f } }, + { VTYPE_PLAIN, { -5.0f, -2.0f, 3.0f } }, /* 97, lower outer vent, left side. */ +}; + +static CompoundVertex ship2vtx2[] = { + { VTYPE_NORM, { 77, 78, 80, static_cast(-1),static_cast(-1)} }, /* 120, retro norm. */ +}; + +static uint16 ship2data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_COMPSMOOTH | RFLAG_XREF, 0, 5, 26, 27, 6, 7, /* Front edge. */ + COMP_HERM_NOTAN, 8, 9, + COMP_HERMITE, 16, 1, 37, 38, + COMP_HERMITE, 14, 1, 49, 48, + COMP_HERMITE, 6, 7, 41, 42, + COMP_END, + PTYPE_COMPSMOOTH | RFLAG_XREF, 1, 5, 28, 29, 8, 9, /* Mid edge. */ + COMP_HERM_NOTAN, 10, 11, + COMP_HERMITE, 22, 1, 37, 38, + COMP_HERM_NOTAN, 16, 1, + COMP_HERMITE, 8, 9, 43, 44, + COMP_END, + PTYPE_COMPSMOOTH | RFLAG_XREF, 2, 5, 30, 31, 10, 11, /* Rear edge. */ + COMP_HERMITE, 12, 13, 53, 54, + COMP_HERMITE, 22, 1, 39, 40, + COMP_HERMITE, 10, 11, 43, 44, + COMP_END, + PTYPE_COMPFLAT | RFLAG_XREF, 3, 5, 32, 1, 16, 1, /* Centre. */ + COMP_HERM_NOTAN, 22, 1, + COMP_HERMITE, 24, 1, 59, 60, + COMP_HERM_NOTAN, 18, 1, + COMP_HERMITE, 16, 1, 47, 51, + COMP_END, + PTYPE_COMPSMOOTH | RFLAG_XREF, 5, 5, 34, 1, 22, 23, /* nacelle. */ + COMP_HERMITE, 12, 0, 45, 46, + COMP_HERM_NOTAN, 35, 0, + COMP_HERMITE, 61, 1, 57, 63, + COMP_HERMITE, 36, 3, 63, 58, + COMP_HERM_NOTAN, 24, 25, + COMP_HERMITE, 22, 23, 59, 60, + COMP_END, + PTYPE_COMPFLAT | RFLAG_XREF, 6, 5, 70, 4, 12, 4, /* Rear underside. */ + COMP_HERMITE, 10, 4, 56, 55, + COMP_LINE, 71, 4, + COMP_LINE, 12, 4, + COMP_END, + PTYPE_QUADFLAT | RFLAG_XREF, 8, 6, 65, 64, /* Other underside. */ + PTYPE_QUADFLAT | RFLAG_XREF, 8, 64, 71, 10, + PTYPE_QUADFLAT | RFLAG_XREF, 64, 65, 67, 66, + PTYPE_TRIFLAT | RFLAG_XREF, 71, 64, 66, + PTYPE_QUADFLAT | RFLAG_XREF, 71, 66, 68, 12, + PTYPE_TRIFLAT | RFLAG_XREF, 12, 68, 35, + PTYPE_QUADFLAT | RFLAG_XREF, 66, 67, 69, 68, + PTYPE_COMPFLAT | RFLAG_XREF, 7, 5, 72, 5, 36, 5, /* Engine back face. */ + COMP_HERMITE, 61, 5, 57, 62, + COMP_HERMITE, 35, 5, 62, 58, + COMP_LINE, 68, 5, + COMP_LINE, 69, 5, + COMP_LINE, 36, 5, + COMP_END, + + PTYPE_MATFIXED, 30, 30, 30, 30, 30, 30, 200, 0, 0, 0, + PTYPE_COMPSMOOTH, 4, 5, 33, 1, 16, 0, /* Cockpit. */ + COMP_HERMITE, 18, 5, 52, 48, + COMP_HERMITE, 20, 3, 48, 51, + COMP_HERMITE, 14, 2, 49, 47, + COMP_HERMITE, 16, 0, 47, 50, + COMP_END, + + PTYPE_ZBIAS, 5, 5, + PTYPE_MATFIXED, 30, 30, 30, 30, 30, 30, 200, 0, 0, 0, + PTYPE_TUBE | RFLAG_XREF, 8, 12, 72, 76, 1, 250, 200, + PTYPE_MATANIM, AFUNC_THRUSTPULSE, + 0, 0, 0, 0, 0, 0, 100, 50, 50, 100, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 50, + PTYPE_CIRCLE | RFLAG_XREF, 9, 12, 72, 5, 1, 200, + + PTYPE_ZBIAS, 120, 5, + // PTYPE_MATFIXED, 30, 30, 30, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT | RFLAG_XREF, 77, 78, 80, 79, + + PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_ZBIAS, 95, 5, + PTYPE_TEXT, 0, 0x8000, 68, 95, 2, 1900, 50, 250, + PTYPE_ZBIAS, 96, 5, + PTYPE_TEXT, 0, 0x8000, 97, 96, 5, 400, 50, 250, + + PTYPE_ZBIAS, 4, 5, + PTYPE_SUBOBJECT, 0, SUB_NWUNIT, 73, 4, 5, 100, + PTYPE_SUBOBJECT, 0, SUB_NWUNIT, 74, 4, 5, 64, + PTYPE_SUBOBJECT, 0, SUB_NWUNIT, 75, 4, 5, 64, + + PTYPE_END, + +}; + +static Thruster ship2thruster[] = { + { 81, 5 | THRUST_NOANG, 30.0f }, + { 82, 5 | THRUST_NOANG, 30.0f }, + { 83, 2 | THRUST_NOANG, 20.0f }, + { 84, 2 | THRUST_NOANG, 20.0f }, + + { 85, 1, 15.0f }, { 86, 4, 15.0f }, + { 87, 1, 15.0f }, { 88, 4, 15.0f }, + { 89, 1, 15.0f }, { 90, 4, 15.0f }, + + { 91, 0, 15.0f }, { 92, 3, 15.0f }, + { 93, 0, 15.0f }, { 94, 3, 15.0f }, +}; + +static Model ship2model = { 1.0f, 98, ship2vtx1, 120, 1, ship2vtx2, + 0, 0, 14, ship2thruster, ship2data, 10 }; + + +static PlainVertex station1vtx1[] = { + { VTYPE_PLAIN, { -15.0f, 30.0f, 20.0f } }, /* 6, front octagon. */ + { VTYPE_PLAIN, { 15.0f, 30.0f, 20.0f } }, + { VTYPE_PLAIN, { 30.0f, 15.0f, 20.0f } }, + { VTYPE_PLAIN, { 30.0f, -15.0f, 20.0f } }, + { VTYPE_PLAIN, { 15.0f, -30.0f, 20.0f } }, + { VTYPE_PLAIN, { -15.0f, -30.0f, 20.0f } }, + + { VTYPE_PLAIN, { -15.0f, 30.0f, -20.0f } }, /* 12, back octagon. */ + { VTYPE_PLAIN, { 15.0f, 30.0f, -20.0f } }, + { VTYPE_PLAIN, { 30.0f, 15.0f, -20.0f } }, + { VTYPE_PLAIN, { 30.0f, -15.0f, -20.0f } }, + { VTYPE_PLAIN, { 15.0f, -30.0f, -20.0f } }, + { VTYPE_PLAIN, { -15.0f, -30.0f, -20.0f } }, + + { VTYPE_PLAIN, { -10.0f, 5.0f, 20.0f } }, /* 18, inlet front. */ + { VTYPE_PLAIN, { 10.0f, 5.0f, 20.0f } }, + { VTYPE_PLAIN, { 10.0f, -5.0f, 20.0f } }, + { VTYPE_PLAIN, { -10.0f, -5.0f, 20.0f } }, + + { VTYPE_PLAIN, { -10.0f, 5.0f, 0.0f } }, /* 22, inlet rear. */ + { VTYPE_PLAIN, { 10.0f, 5.0f, 0.0f } }, + { VTYPE_PLAIN, { 10.0f, -5.0f, 0.0f } }, + { VTYPE_PLAIN, { -10.0f, -5.0f, 0.0f } }, + + + { VTYPE_PLAIN, { 30.0f, 10.0f, 10.0f } }, /* 26, strut inner. */ + { VTYPE_PLAIN, { 30.0f, -10.0f, 10.0f } }, + { VTYPE_PLAIN, { 30.0f, -10.0f, -10.0f } }, + { VTYPE_PLAIN, { 30.0f, 10.0f, -10.0f } }, + + { VTYPE_PLAIN, { 100.0f, 10.0f, 10.0f } }, /* 30, strut outer. */ + { VTYPE_PLAIN, { 100.0f, -10.0f, 10.0f } }, + { VTYPE_PLAIN, { 100.0f, -10.0f, -10.0f } }, + { VTYPE_PLAIN, { 100.0f, 10.0f, -10.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, 25.0f } }, /* 34, ring start, end. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -25.0f } }, + +#if 0 + { VTYPE_PLAIN, { 0.0f, 120.0f, 15.0f } }, /* 34, ring top. */ + { VTYPE_PLAIN, { 0.0f, 100.0f, 15.0f } }, + { VTYPE_PLAIN, { 0.0f, 100.0f, -15.0f } }, + { VTYPE_PLAIN, { 0.0f, 120.0f, -15.0f } }, + + { VTYPE_PLAIN, { 103.9230f, 60.0f, 15.0f } }, /* 38, ring top right. */ + { VTYPE_PLAIN, { 86.60254f, 50.0f, 15.0f } }, + { VTYPE_PLAIN, { 86.60254f, 50.0f, -15.0f } }, + { VTYPE_PLAIN, { 103.9230f, 60.0f, -15.0f } }, + + { VTYPE_PLAIN, { 103.9230f, -60.0f, 15.0f } }, /* 42, ring bottom right. */ + { VTYPE_PLAIN, { 86.60254f, -50.0f, 15.0f } }, + { VTYPE_PLAIN, { 86.60254f, -50.0f, -15.0f } }, + { VTYPE_PLAIN, { 103.9230f, -60.0f, -15.0f } }, + + { VTYPE_PLAIN, { 0.0f, -120.0f, 15.0f } }, /* 46, ring bottom. */ + { VTYPE_PLAIN, { 0.0f, -100.0f, 15.0f } }, + { VTYPE_PLAIN, { 0.0f, -100.0f, -15.0f } }, + { VTYPE_PLAIN, { 0.0f, -120.0f, -15.0f } }, + + { VTYPE_DIR, { 0.8660254f, 0.5f, 0.0f } }, /* 50, ring normals. */ + { VTYPE_DIR, { -0.8660254ff, -0.5f, 0.0f } }, + { VTYPE_DIR, { 0.8660254ff, -0.5f, 0.0f } }, + { VTYPE_DIR, { -0.8660254ff, 0.5f, 0.0f } }, + + { VTYPE_PLAIN, { 120.0f, 0.0f, 0.0f } }, /* 54, top tangents. */ + { VTYPE_PLAIN, { 100.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { -60.0f, 104.0f, 0.0f } }, /* 56, top right tangents. */ + { VTYPE_PLAIN, { -50.0f, 86.6f, 0.0f } }, + { VTYPE_PLAIN, { -60.0f, -104.0f, 0.0f } }, /* 58, bottom right tangents. */ + { VTYPE_PLAIN, { -50.0f, -86.6f, 0.0f } }, + { VTYPE_PLAIN, { -120.0f, 0.0f, 0.0f } }, /* 60, bottom tangents. */ + { VTYPE_PLAIN, { -100.0f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 60.0f, 103.9230f, 0.0f } }, /* 61, outer midpoints. */ + { VTYPE_PLAIN, { 120.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 60.0f, -103.9230f, 0.0f } }, + + { VTYPE_PLAIN, { 50.0f, 86.60254f, 0.0f } }, /* 64, inner midpoints. */ + { VTYPE_PLAIN, { 100.0f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 50.0f, -86.60254f, 0.0f } }, + + { VTYPE_DIR, { 0.5f, 0.8660254f, 0.0f } }, /* 67, midpoint normals. */ + { VTYPE_DIR, { -0.5f, -0.8660254f, 0.0f } }, + { VTYPE_DIR, { 0.5f, -0.8660254f, 0.0f } }, + { VTYPE_DIR, { -0.5f, 0.8660254f, 0.0f } }, + + { VTYPE_PLAIN, { 60.0f, 103.9230f, 15.0f } }, /* 71, forward ring midpoints. */ + { VTYPE_PLAIN, { 120.0f, 0.0f, 15.0f } }, + { VTYPE_PLAIN, { 60.0f, -103.9230f, 15.0f } }, + + { VTYPE_PLAIN, { 60.0f, 103.9230f, -15.0f } }, /* 74, back ring midpoints. */ + { VTYPE_PLAIN, { 120.0f, 0.0f, -15.0f } }, + { VTYPE_PLAIN, { 60.0f, -103.9230f, -15.0f } }, + + { VTYPE_PLAIN, { -60.0f, 104.0f, 0.0f } }, /* 77, top right AC tangents. */ + { VTYPE_PLAIN, { -50.0f, 86.6f, 0.0f } }, + { VTYPE_PLAIN, { -60.0f, -104.0f, 0.0f } }, /* 79, bottom right AC tangents. */ + { VTYPE_PLAIN, { -50.0f, -86.6f, 0.0f } }, +#endif +}; + +static CompoundVertex station1vtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1),static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 station1data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT, 7, 6, 18, 19, /* Front face. */ + PTYPE_QUADFLAT | RFLAG_XREF, 9, 8, 7, 19, + PTYPE_QUADFLAT | RFLAG_XREF, 10, 9, 19, 20, + PTYPE_QUADFLAT, 11, 10, 20, 21, + + PTYPE_QUADFLAT | RFLAG_XREF, 13, 14, 15, 16, /* Back face. */ + PTYPE_QUADFLAT, 12, 13, 16, 17, + + PTYPE_QUADFLAT, 6, 7, 13, 12, /* Sides. */ + PTYPE_QUADFLAT | RFLAG_XREF, 7, 8, 14, 13, + PTYPE_QUADFLAT | RFLAG_XREF, 8, 9, 15, 14, + PTYPE_QUADFLAT | RFLAG_XREF, 9, 10, 16, 15, + PTYPE_QUADFLAT, 10, 11, 17, 16, + + PTYPE_QUADFLAT, 19, 18, 22, 23, /* Inlet. */ + PTYPE_QUADFLAT | RFLAG_XREF, 20, 19, 23, 24, + PTYPE_QUADFLAT, 21, 20, 24, 25, + PTYPE_QUADFLAT, 23, 22, 25, 24, + + PTYPE_QUADFLAT | RFLAG_XREF, 26, 27, 31, 30, + PTYPE_QUADFLAT | RFLAG_XREF, 27, 28, 32, 31, + PTYPE_QUADFLAT | RFLAG_XREF, 28, 29, 33, 32, + PTYPE_QUADFLAT | RFLAG_XREF, 29, 26, 30, 33, + + PTYPE_TUBE | RFLAG_XREF, 0, 38, 34, 35, 1, 11500, 10000, + + // PTYPE_QUADFLAT | RFLAG_XREF, + // PTYPE_SUBOBJECT, 0x8000, SUB_NOSEWHEEL, 10, 0, 4, 100, + + PTYPE_END, +}; + +static Model station1model = { 1.0f, 36, station1vtx1, 100, 0, station1vtx2, + 0, 0, 0, 0, station1data, 1 }; + +static PlainVertex ship3vtx1[] = { + { VTYPE_PLAIN, { 4.0f, -5.0f, 20.0f } }, /* 6, nose pair. */ + { VTYPE_PLAIN, { -4.0f, -5.0f, 20.0f } }, + + { VTYPE_PLAIN, { 6.0f, 4.0f, 10.0f } }, /* 8, mid vertices. */ + { VTYPE_PLAIN, { -6.0f, 4.0f, 10.0f } }, + + { VTYPE_PLAIN, { 14.0f, -5.0f, 10.0f } }, /* 10, front quarter. */ + { VTYPE_PLAIN, { 10.0f, 5.0f, -10.0f } }, /* Back mid. */ + { VTYPE_PLAIN, { 30.0f, -5.0f, -10.0f } }, /* Back end. */ + + // { VTYPE_PLAIN, { 20.0f, 1.0f, 0.0f } }, /* 13, curve midpoint. */ + // { VTYPE_DIR, { 2.0f, 2.0f, 1.0f } }, /* norm. */ + + { VTYPE_PLAIN, { 18.75f, 1.25f, -2.1875f } }, /* 13, curve midpoint. */ + { VTYPE_DIR, { 0.707f, 1.0f, 0.707f } }, /* norm. */ + + { VTYPE_PLAIN, { 15.0f, 0.0f, -10.0f } }, /* 15, back midpoint. */ + { VTYPE_PLAIN, { 30.0f, -5.0f, -10.0f } }, /* Underside midpoint. */ + + // CW tangents + { VTYPE_PLAIN, { -4.0f, -1.0f, 20.0f } }, /* 17, 11->10 start. */ + { VTYPE_PLAIN, { 8.0f, -9.0f, 0.0f } }, /* 11->10 end. */ + + { VTYPE_PLAIN, { 16.0f, 0.0f, 0.0f } }, /* 19, 10->12 start. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -20.0f } }, /* 10-12 end. */ + + { VTYPE_PLAIN, { 0.0f, 10.0f, 0.0f } }, /* 21, 12->11 start. */ + { VTYPE_PLAIN, { -20.0f, 0.0f, 0.0f } }, /* 12-11 end. */ + + // CCW tangents + { VTYPE_PLAIN, { -8.0f, 9.0f, 0.0f } }, /* 23, 10->11 start. */ + { VTYPE_PLAIN, { 4.0f, 1.0f, -20.0f } }, /* 10->11 end. */ + + { VTYPE_PLAIN, { 0.0f, 0.0f, 20.0f } }, /* 25, 12-10 start. */ + { VTYPE_PLAIN, { -16.0f, 0.0f, 0.0f } }, /* 12->10 end. */ + + { VTYPE_PLAIN, { 20.0f, 0.0f, 0.0f } }, /* 27, 11-12 start. */ + { VTYPE_PLAIN, { 0.0f, -10.0f, 0.0f } }, /* 11->12 end. */ + + { VTYPE_PLAIN, { -10.0f, 5.0f, -10.0f } }, /* 29, back mid, left side. */ + { VTYPE_PLAIN, { -14.0f, -5.0f, 10.0f } }, /* 30 front quarter, left side. */ + { VTYPE_PLAIN, { 10.0f, -5.0f, -10.0f } }, /* Back mid, right underside. */ + { VTYPE_PLAIN, { -10.0f, -5.0f, -10.0f } }, /* Back mid, left underside. */ + + { VTYPE_PLAIN, { 12.0f, 0.0f, -10.0f } }, /* 33, back thruster. */ + { VTYPE_PLAIN, { 12.0f, 0.0f, -13.0f } }, /* Back thruster end. */ + + { VTYPE_PLAIN, { 0.0f, -5.0f, 13.0f } }, /* 35, nose gear. */ + { VTYPE_PLAIN, { 15.0f, -5.0f, -3.0f } }, /* 36, back gear. */ + { VTYPE_PLAIN, { -15.0f, -5.0f, -3.0f } }, /* 37, back gear. */ + + // thruster jets + { VTYPE_PLAIN, { 12.0f, 0.0f, -13.0f } }, /* 38, main. */ + { VTYPE_PLAIN, { 15.0f, -3.0f, 9.0f } }, /* Retro. */ + + { VTYPE_PLAIN, { 30.0f, -4.0f, -9.0f } }, /* 40, corner clusters. */ + { VTYPE_PLAIN, { 29.0f, -5.5f, -9.0f } }, /* Down. */ + { VTYPE_PLAIN, { 29.0f, -4.0f, -9.0f } }, /* Up. */ + { VTYPE_PLAIN, { 10.0f, 0.0f, 11.0f } }, /* Lateral front. */ + +}; + +static CompoundVertex ship3vtx2[] = { + { VTYPE_NORM, { 15, 8, 10, static_cast(-1), static_cast(-1) } }, /* 100, mid curve norm. */ + { VTYPE_NORM, { 9, 8, 11, static_cast(-1), static_cast(-1) } }, /* 101, top curve norm. */ +}; + +static uint16 ship3data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_QUADFLAT, 6, 8, 9, 7, + PTYPE_QUADFLAT, 9, 8, 11, 29, + PTYPE_TRIFLAT | RFLAG_XREF, 8, 6, 10, + PTYPE_QUADFLAT, 10, 6, 7, 30, + PTYPE_QUADFLAT, 32, 31, 10, 30, + PTYPE_QUADFLAT, 29, 11, 31, 32, + + PTYPE_COMPFLAT | RFLAG_XREF, 0, 5, 8, 100, 8, 100, /* mid curve. */ + COMP_LINE, 10, 100, + COMP_HERMITE, 11, 100, 23, 24, + COMP_LINE, 8, 100, + COMP_END, + PTYPE_COMPSMOOTH | RFLAG_XREF, 1, 5, 13, 14, 11, 101, /* top curve. */ + COMP_HERMITE, 10, 2, 17, 18, + COMP_HERMITE, 12, 0, 19, 20, + COMP_HERMITE, 11, 101, 21, 22, + COMP_STEPS, 10, + COMP_END, + PTYPE_COMPFLAT | RFLAG_XREF, 2, 5, 15, 5, 11, 5, /* back curve. */ + COMP_HERMITE, 12, 5, 27, 28, + COMP_LINE, 31, 5, + COMP_LINE, 11, 5, + COMP_END, + PTYPE_COMPFLAT | RFLAG_XREF, 3, 5, 16, 4, 12, 4, /* underside curve. */ + COMP_HERMITE, 10, 4, 25, 26, + COMP_LINE, 31, 4, + COMP_LINE, 12, 4, + COMP_END, + + PTYPE_ZBIAS, 5, 5, + PTYPE_MATFIXED, 30, 30, 30, 30, 30, 30, 200, 0, 0, 0, + PTYPE_TUBE | RFLAG_XREF, 4, 12, 33, 34, 1, 300, 250, + PTYPE_MATANIM, AFUNC_THRUSTPULSE, + 0, 0, 0, 0, 0, 0, 100, 50, 50, 100, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 50, + PTYPE_CIRCLE | RFLAG_XREF, 5, 12, 33, 5, 1, 250, + + // PTYPE_ZBIAS, 120, 5, + // PTYPE_MATFIXED, 30, 30, 30, 0, 0, 0, 100, 0, 0, 0, + // PTYPE_QUADFLAT | RFLAG_XREF, 77, 78, 80, 79, + + /* PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_ZBIAS, 95, 5, + PTYPE_TEXT, 0, 0x8000, 68, 95, 2, 1900, 50, 250, + PTYPE_ZBIAS, 96, 5, + PTYPE_TEXT, 0, 0x8000, 97, 96, 5, 400, 50, 250, + */ + PTYPE_ZBIAS, 4, 5, + PTYPE_SUBOBJECT, 0, SUB_NWUNIT, 35, 4, 5, 100, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 36, 4, 5, 100, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 37, 4, 5, 100, + + PTYPE_END, +}; + +static Thruster ship3thruster[] = { + { 38, 5 | THRUST_NOANG | THRUST_XREF, 30.0f }, + { 39, 2 | THRUST_NOANG | THRUST_XREF, 20.0f }, + { 40, 0 | THRUST_XREF, 15.0f }, + { 41, 4 | THRUST_XREF, 15.0f }, + { 42, 1 | THRUST_XREF, 15.0f }, + { 43, 0 | THRUST_XREF, 15.0f }, +}; + +static Model ship3model = { 1.0f, 44, ship3vtx1, 100, 2, ship3vtx2, + 0, 0, 6, ship3thruster, ship3data, 6 }; + +static PlainVertex ship4vtx1[] = { + { VTYPE_PLAIN, { -4.0f, -3.0f, 35.0f } }, /* 6, nose vertices. */ + { VTYPE_PLAIN, { 4.0f, -3.0f, 35.0f } }, + { VTYPE_PLAIN, { 1.0f, -7.0f, 32.0f } }, + { VTYPE_PLAIN, { -1.0f, -7.0f, 32.0f } }, + + { VTYPE_PLAIN, { -6.0f, 8.0f, 20.0f } }, /* 10, nose section back. */ + { VTYPE_PLAIN, { 6.0f, 8.0f, 20.0f } }, /* And extrusion area. */ + { VTYPE_PLAIN, { 10.0f, 4.0f, 20.0f } }, + { VTYPE_PLAIN, { 10.0f, -4.0f, 20.0f } }, + { VTYPE_PLAIN, { 6.0f, -8.0f, 20.0f } }, + { VTYPE_PLAIN, { -6.0f, -8.0f, 20.0f } }, + { VTYPE_PLAIN, { -10.0f, -4.0f, 20.0f } }, + { VTYPE_PLAIN, { -10.0f, 4.0f, 20.0f } }, + + /* Midpoints. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, 20.0f } }, /* 18 */ + { VTYPE_PLAIN, { 0.0f, 0.0f, 16.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -4.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -8.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, -26.0f } }, + + { VTYPE_PLAIN, { 0.3826834f, 0.9238795f, 0.0f } }, /* 23, tube norm. */ + + { VTYPE_PLAIN, { 12.5f, 2.0f, -10.0f } }, /* 24, top engine. */ + { VTYPE_PLAIN, { 12.5f, 2.0f, -30.0f } }, + { VTYPE_PLAIN, { 12.5f, 2.0f, -13.0f } }, + { VTYPE_PLAIN, { 12.5f, 2.0f, -27.0f } }, + + { VTYPE_PLAIN, { 11.5f, -6.0f, -10.0f } }, /* 28, bottom engine. */ + { VTYPE_PLAIN, { 11.5f, -6.0f, -30.0f } }, + { VTYPE_PLAIN, { 11.5f, -6.0f, -13.0f } }, + { VTYPE_PLAIN, { 11.5f, -6.0f, -27.0f } }, + + { VTYPE_PLAIN, { 10.0f, -4.0f, -4.0f } }, /* 32, right text pos. */ + { VTYPE_PLAIN, { -10.0f, -4.0f, 16.0f } }, /* Left text pos. */ + + { VTYPE_PLAIN, { 5.0f, -8.0f, 13.0f } }, /* 34, gear pos. */ + { VTYPE_PLAIN, { -5.0f, -8.0f, 13.0f } }, + { VTYPE_PLAIN, { 11.5f, -8.309f, -25.0f } }, /* 36, gear pos. */ + { VTYPE_PLAIN, { -11.5f, -8.309f, -25.0f } }, + { VTYPE_PLAIN, { 11.5f, -8.309f, -13.0f } }, /* 38, gear pos. */ + { VTYPE_PLAIN, { -11.5f, -8.309f, -13.0f } }, + + { VTYPE_PLAIN, { 0.05f, 8.0f, -15.0f } }, /* 40, dish pos. */ +}; + +static CompoundVertex ship4vtx2[] = { + { VTYPE_ANIMROTATE,{1,0,static_cast(-1),static_cast(-1),AFUNC_LIN4SEC } },/* Dummy. */ +}; + +static uint16 ship4data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + + PTYPE_QUADFLAT, 6, 7, 11, 10, /* Front section. */ + PTYPE_TRIFLAT | RFLAG_XREF, 7, 12, 11, + PTYPE_TRIFLAT | RFLAG_XREF, 7, 13, 12, + PTYPE_TRIFLAT | RFLAG_XREF, 7, 14, 13, + PTYPE_TRIFLAT | RFLAG_XREF, 7, 9, 14, + PTYPE_QUADFLAT, 7, 6, 9, 8, + PTYPE_QUADFLAT, 8, 9, 15, 14, + + PTYPE_QUADFLAT, 10, 11, 14, 15, + PTYPE_QUADFLAT | RFLAG_XREF, 11, 12, 13, 14, + + PTYPE_EXTRUSION, 0, 8, 19, 20, 1, 100, 10, + PTYPE_EXTRUSION, 1, 8, 21, 22, 1, 100, 10, + + PTYPE_TUBE | RFLAG_XREF, 2, 8, 24, 25, 23, 250, 200, + PTYPE_TUBE | RFLAG_XREF, 3, 8, 28, 29, 23, 250, 200, + + PTYPE_MATANIM, AFUNC_THRUSTPULSE, + 0, 0, 0, 0, 0, 0, 100, 50, 50, 100, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 50, + PTYPE_CIRCLE | RFLAG_XREF, 4, 8, 26, 2, 23, 200, + PTYPE_CIRCLE | RFLAG_XREF, 5, 8, 27, 5, 23, 200, + PTYPE_CIRCLE | RFLAG_XREF, 6, 8, 30, 2, 23, 200, + PTYPE_CIRCLE | RFLAG_XREF, 7, 8, 31, 5, 23, 200, + + PTYPE_MATFIXED, 30, 30, 30, 10, 10, 10, 100, 0, 0, 0, + PTYPE_EXTRUSION, 8, 8, 18, 19, 1, 85, 10, + PTYPE_EXTRUSION, 9, 8, 20, 21, 1, 85, 10, + + PTYPE_MATFIXED, 20, 20, 20, 0, 0, 0, 100, 0, 0, 0, + PTYPE_ZBIAS, 0, 5, + PTYPE_TEXT, 0, 0x8000, 32, 0, 2, 300, 250, 400, + PTYPE_ZBIAS, 3, 5, + PTYPE_TEXT, 0, 0x8000, 33, 3, 5, 300, 250, 400, + + PTYPE_ZBIAS, 4, 5, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 34, 4, 5, 60, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 35, 4, 5, 60, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 36, 4, 5, 50, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 37, 4, 5, 50, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 38, 4, 5, 50, + PTYPE_SUBOBJECT, 0, SUB_MWUNIT, 39, 4, 5, 50, + + PTYPE_ZBIAS, 1, 5, + PTYPE_SUBOBJECT, 0x8000, SUB_DISH, 40, 1, 100, 200, + + PTYPE_END, +}; + +static Thruster ship4thruster[] = { + { 25, 5 | THRUST_NOANG | THRUST_XREF, 30.0f }, + { 29, 5 | THRUST_NOANG | THRUST_XREF, 30.0f }, + { 24, 2 | THRUST_NOANG | THRUST_XREF, 20.0f }, + { 28, 2 | THRUST_NOANG | THRUST_XREF, 20.0f }, + // { 40, 0 | THRUST_XREF, 15.0f }, + // { 41, 4 | THRUST_XREF, 15.0f }, + // { 42, 1 | THRUST_XREF, 15.0f }, + // { 43, 0 | THRUST_XREF, 15.0f }, +}; +static Model ship4model = { 1.0f, 41, ship4vtx1, 100, 1, ship4vtx2, + 0, 0, 4, ship4thruster, ship4data, 10 }; + +static PlainVertex dishvtx1[] = { + { VTYPE_PLAIN, { 0.0f, 3.0f, 1.2f } }, /* 6, dish. */ + { VTYPE_PLAIN, { 1.0f, 2.0f, 1.2f } }, + { VTYPE_PLAIN, { 0.0f, 1.0f, 1.2f } }, + { VTYPE_PLAIN, { -1.0f, 2.0f, 1.2f } }, + { VTYPE_PLAIN, { 0.0f, 2.0f, 0.2f } }, + + { VTYPE_PLAIN, { 0.0f, 2.2f, 0.0f } }, /* 11, stand. */ + { VTYPE_PLAIN, { 0.0f, 0.6f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 0.0f, 0.0f } }, + + { VTYPE_PLAIN, { 0.0f, 2.0f, 1.7f } }, /* 14, antenna. */ + + { VTYPE_PLAIN, { 1.5f, 0.0f, 0.0f } }, /* 15, tangents. */ + { VTYPE_PLAIN, { -1.5f, 0.0f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, 1.5f, 0.0f } }, + { VTYPE_PLAIN, { 0.0f, -1.5f, 0.0f } }, + +}; + +static CompoundVertex dishvtx2[] = { + { VTYPE_CROSS, { 0, 1, 2, static_cast(-1),static_cast(-1) } }, /* Dummy. */ +}; + +static uint16 dishdata[] = { + PTYPE_MATFIXED, 50, 50, 50, 100, 100, 100, 200, 0, 0, 0, + PTYPE_COMPSMOOTH, 0, 5, 10, 5, 6, 1, + COMP_HERMITE, 7, 0, 15, 18, + COMP_HERMITE, 8, 4, 18, 16, + COMP_HERMITE, 9, 3, 16, 17, + COMP_HERMITE, 6, 1, 17, 15, + COMP_END, + PTYPE_COMPSMOOTH, 1, 5, 10, 2, 6, 4, + COMP_HERMITE, 9, 0, 16, 18, + COMP_HERMITE, 8, 1, 18, 15, + COMP_HERMITE, 7, 3, 15, 17, + COMP_HERMITE, 6, 4, 17, 16, + COMP_END, + PTYPE_CYLINDER, 4, 6, 10, 14, 0, 10, + + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_CYLINDER, 2, 6, 11, 12, 0, 20, + PTYPE_CYLINDER, 3, 6, 12, 13, 0, 70, + + PTYPE_END, +}; + +static Model dishmodel = { 1.0f, 19, dishvtx1, 40, 0, dishvtx2, + 0, 0, 0, 0, dishdata, 5 }; + +static PlainVertex ship5vtx1[] = { + { VTYPE_PLAIN, { -1.0f, 0.0f, 20.0f } }, /* 6, right nose vertex. */ + { VTYPE_PLAIN, { 0.0f, 1.0f, 0.4f } }, + { VTYPE_PLAIN, { 0.0f, -1.0f, 0.4f } }, + + { VTYPE_PLAIN, { 1.0f, 0.0f, 20.0f } }, /* 9, left nose vertex. */ + { VTYPE_PLAIN, { 0.0f, 1.0f, 0.4f } }, + { VTYPE_PLAIN, { 0.0f, -1.0f, 0.4f } }, + + { VTYPE_PLAIN, { -2.0f, 2.0f, 10.0f } }, /* 12, nose section back */ + { VTYPE_PLAIN, { 2.0f, 2.0f, 10.0f } }, /* and extrusion area. */ + { VTYPE_PLAIN, { 3.0f, 0.0f, 10.0f } }, + { VTYPE_PLAIN, { 2.0f, -2.0f, 10.0f } }, + { VTYPE_PLAIN, { -2.0f, -2.0f, 10.0f } }, + { VTYPE_PLAIN, { -3.0f, 0.0f, 10.0f } }, + + { VTYPE_PLAIN, { 0.0f, 0.0f, 10.0f } }, /* 18, extrusion start/end. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -15.0f } }, + + /* Tangents. */ + { VTYPE_PLAIN, { 1.0f, 0.0f, 10.0f } }, /* 20, 12->6 and 16->6 s. */ + { VTYPE_PLAIN, { 1.0f, -4.0f, 10.f } }, /* 12->6 e. */ + { VTYPE_PLAIN, { -1.0f, 4.0f, -10.0f } }, /* 6-12 e. */ + { VTYPE_PLAIN, { -1.0f, 0.0f, -10.0f } }, /* 6->12 and 6->16 s. */ + + { VTYPE_PLAIN, { -1.0f, 0.0f, 10.0f } }, /* 24, 13->9. */ + { VTYPE_PLAIN, { -1.0f, -4.0f, 10.0f } }, + { VTYPE_PLAIN, { 1.0f, 4.0f, -10.0f } }, + { VTYPE_PLAIN, { 1.0f, 0.0f, -10.0f } }, /* 9->13 and 9-> */ + + { VTYPE_PLAIN, { 1.0f, 4.0f, 10.0f } }, /* 28, 16->6 e. */ + { VTYPE_PLAIN, { -1.0f, -4.0f, -10.0f } }, /* 6-16 e. */ + + { VTYPE_PLAIN, { -1.0f, 4.0f, 10.0f } }, /* 30, 15->9 e. */ + { VTYPE_PLAIN, { 1.0f, -4.0f, 10.0f } }, /* 9-15 e. */ + + { VTYPE_PLAIN, { 0.0f, 1.333f, 15.0f } }, /* 32, nose top midpoint. */ + { VTYPE_PLAIN, { 0.0f, 1.0f, 0.2f } }, + + { VTYPE_PLAIN, { 0.0f, -1.333f, 15.0f } }, /* 34, nose bottom midpoint. */ + { VTYPE_PLAIN, { 0.0f, -1.0f, 0.2f } }, + + /* Wing positions. */ + { VTYPE_PLAIN, { 2.5f, 1.0f, -5.0f } }, /* 36. */ + { VTYPE_PLAIN, { 2.5f, -1.0f, -5.0f } }, + { VTYPE_PLAIN, { -2.5f, -1.0f, -5.0f } }, + { VTYPE_PLAIN, { -2.5f, 1.0f, -5.0f } }, + + /* Wing normals. */ + { VTYPE_DIR, { 2.0f, 1.0f, 0.0f } }, /* 40. */ + { VTYPE_DIR, { 2.0f, -1.0f, 0.0f } }, + { VTYPE_DIR, { -2.0f, -1.0f, 0.0f } }, + { VTYPE_DIR, { -2.0f, 1.0f, 0.0f } }, +}; + +static CompoundVertex ship5vtx2[] = { + { VTYPE_NORM, {9,14,13,static_cast(-1),static_cast(-1)}}, /* 100, nose side normals. */ + { VTYPE_NORM, {9,15,14,static_cast(-1),static_cast(-1)}}, +}; + +static uint16 ship5data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + + PTYPE_EXTRUSION, 0, 6, 18, 19, 1, 100, 12, + + PTYPE_COMPSMOOTH, 1, 5, 32, 33, 13, 1, + COMP_LINE, 12, 1, + COMP_HERMITE, 6, 7, 20, 21, + COMP_LINE, 9, 10, + COMP_HERMITE, 13, 1, 26, 27, + COMP_END, + PTYPE_COMPSMOOTH, 2, 5, 34, 35, 16, 4, + COMP_LINE, 15, 4, + COMP_HERMITE, 9, 11, 24, 30, + COMP_LINE, 6, 8, + COMP_HERMITE, 16, 4, 29, 23, + COMP_END, + + PTYPE_COMPFLAT | RFLAG_XREF, 3, 5, 14, 100, 13, 100, + COMP_HERMITE, 0, 100, 24, 25, + COMP_LINE, 14, 100, + COMP_LINE, 13, 100, + COMP_END, + PTYPE_COMPFLAT | RFLAG_XREF, 4, 5, 14, 101, 9, 101, + COMP_HERMITE, 15, 101, 31, 27, + COMP_LINE, 14, 101, + COMP_LINE, 9, 101, + COMP_END, + + PTYPE_SUBOBJECT, 0x8000, SUB_WING2, 36, 40, 2, 70, + PTYPE_SUBOBJECT, 0x8000, SUB_WING2, 37, 41, 2, 70, + PTYPE_SUBOBJECT, 0x8000, SUB_WING2, 38, 42, 2, 70, + PTYPE_SUBOBJECT, 0x8000, SUB_WING2, 39, 43, 2, 70, + + PTYPE_END, +}; + +static Model ship5model = { 1.0f, 44, ship5vtx1, 100, 2, ship5vtx2, + 0, 0, 0, 0, ship5data, 5 }; + +static PlainVertex wing2vtx1[] = { + { VTYPE_PLAIN, { 0.0f, 0.0f, 3.5f } }, /* 6, bottom front. */ + { VTYPE_PLAIN, { 0.0f, 0.0f, -3.5f } }, /* Bottom back. */ + { VTYPE_PLAIN, { 0.0f, 20.0f, 3.5f } }, /* Top front. */ + { VTYPE_PLAIN, { 0.0f, 20.0f, -3.5f } }, /* Top back. */ + + { VTYPE_DIR, { 0.0f, 0.0f, 1.0f } }, /* 10, front norm. */ + { VTYPE_DIR, { 3.0f, 0.0f, -1.0f } }, /* Back, norm. */ + + { VTYPE_PLAIN, { 0.8f, 10.0f, 0.0f } }, /* 12, sidecenter. */ + { VTYPE_DIR, { 1.0f, 0.0f, 0.20f } }, /* Sidenorm. */ + + { VTYPE_PLAIN, { -2.8f, 0.0f, 0.0f } }, /* 14, front tan, forward. */ + { VTYPE_PLAIN, { 2.8f, 0.0f, 0.0f } }, /* Front tan, backward. */ + + { VTYPE_PLAIN, { 1.0f, 0.0f, 3.0f } }, /* 16, back tan, forward. */ + { VTYPE_PLAIN, { -1.0f, 0.0f, -3.0f } }, /* Back tan, backward. */ + + { VTYPE_PLAIN, { 0.3826834f, 0.9238795f, 0.0f } }, /* 18, tube norm. */ + { VTYPE_PLAIN, { 0.0f, 21.5f, 5.0f } }, /* Tube start. */ + { VTYPE_PLAIN, { 0.0f, 21.5f, -5.0f } }, + { VTYPE_PLAIN, { 0.0f, 22.0f, 4.0f } }, + { VTYPE_PLAIN, { 0.0f, 22.0f, -4.0f } }, +}; + +static CompoundVertex wing2vtx2[] = { + {VTYPE_CROSS,{19,14,static_cast(-1),static_cast(-1),static_cast(-1)}},/*Dummy.*/ +}; + +static uint16 wing2data[] = { + PTYPE_MATFIXED, 100, 0, 100, 0, 0, 0, 100, 0, 0, 0, + PTYPE_COMPSMOOTH | RFLAG_XREF, 0, 10, 12, 13, 6, 10, /* Side. */ + COMP_HERMITE, 7, 11, 15, 17, + COMP_HERM_NOTAN, 9, 11, + COMP_HERMITE, 8, 10, 16, 14, + COMP_HERM_NOTAN, 6, 10, + COMP_END, + + PTYPE_TUBE, 1, 8, 19, 20, 18, 162, 140, + + PTYPE_END, +}; + +static Thruster wing2thruster[] = { + { 20, 5, 25.0f }, + { 19, 2, 20.0f }, +}; + +static Model wing2model = { 1.0f, 23, wing2vtx1, 30, 0, wing2vtx2, + 0, 0, 2, wing2thruster, wing2data, 2 }; + +Model* ppModel[] = { + &ship5model, + &wing2model, + &dishmodel, + &nosewheelmodel, + &wingmodel, + &nacellemodel, + &nwunitmodel, + &mainwheelmodel, + &mwunitmodel, + &cylmodel, + &ship2model, + &shipmodel, + &station1model, + &ship3model, + &ship4model, + 0, +}; + diff --git a/src/sbre/primfunc.cpp b/src/sbre/primfunc.cpp new file mode 100644 index 0000000..9f75bed --- /dev/null +++ b/src/sbre/primfunc.cpp @@ -0,0 +1,734 @@ +#include +#include +#include "sbre_int.h" +#include "sbre_anim.h" +#include "sbre.h" /* For subobject. */ +#include "../glfreetype.h" + + +/* +uint16 PFUNC_MATANIM + uint16 animfunc + uint16 dr1, dg1, db1, sr1, sg1, sb1, sh1, er1, eg1, eb1 + uint16 dr2, dg2, db2, sr2, sg2, sb2, sh2, er2, eg2, eb2 +*/ + +static int PrimFuncMatAnim(uint16* pData, Model* pMod, RState* pState) { + float anim = 0.01f * ResolveAnim(pState->pObjParam, pData[1]); + float ianim = 0.01f - anim; + + int i; + float pDiff[4] = { 0, 0, 0, 1.0f }, shiny; + float pSpec[4] = { 0, 0, 0, 1.0f }; + float pEmis[4] = { 0, 0, 0, 1.0f }; + for (i=0; i<3; i++) pDiff[i] = pData[i+2] * anim + pData[i+12] * ianim; + for (i=0; i<3; i++) pSpec[i] = pData[i+5] * anim + pData[i+15] * ianim; + for (i=0; i<3; i++) pEmis[i] = pData[i+9] * anim + pData[i+19] * ianim; + shiny = pData[8] * anim + pData[18] * ianim; + + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pDiff); + glMaterialfv(GL_FRONT, GL_SPECULAR, pSpec); + glMaterialfv(GL_FRONT, GL_EMISSION, pEmis); + glMaterialf(GL_FRONT, GL_SHININESS, shiny); + + return 22; +} + +/* +uint16 PFUNC_MATFIXED + uint16 dr, dg, db + uint16 sr, sg, sb + uint16 shiny + uint16 er, eg, eb +*/ + +static int PrimFuncMatFixed(uint16* pData, Model* pMod, RState* pState) { + int i; + float pDiff[4] = { 0, 0, 0, 1.0f }, shiny; + float pSpec[4] = { 0, 0, 0, 1.0f }; + float pEmis[4] = { 0, 0, 0, 1.0f }; + for(i=0; i<3; i++) pDiff[i] = pData[i+1] * 0.01f; + for(i=0; i<3; i++) pSpec[i] = pData[i+4] * 0.01f; + for(i=0; i<3; i++) pEmis[i] = pData[i+8] * 0.01f; + shiny = pData[7] * 0.01f; + + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pDiff); + glMaterialfv(GL_FRONT, GL_SPECULAR, pSpec); + glMaterialfv(GL_FRONT, GL_EMISSION, pEmis); + glMaterialf(GL_FRONT, GL_SHININESS, shiny); + + return 11; +} + +/* +uint16 PFUNC_MATVAR + uint16 index +*/ + +static int PrimFuncMatVar(uint16* pData, Model* pMod, RState* pState) { + int i; + float pDiff[4] = { 0, 0, 0, 1.0f }, shiny; + float pSpec[4] = { 0, 0, 0, 1.0f }; + float pEmis[4] = { 0, 0, 0, 1.0f }; + ObjParams* pParam = pState->pObjParam; + for(i=0; i<3; i++) pDiff[i] = pParam->pColor[pData[1]].pDiff[i]; + for(i=0; i<3; i++) pSpec[i] = pParam->pColor[pData[1]].pSpec[i]; + for(i=0; i<3; i++) pEmis[i] = pParam->pColor[pData[1]].pEmis[i]; + shiny = pParam->pColor[pData[1]].shiny; + + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, pDiff); + glMaterialfv(GL_FRONT, GL_SPECULAR, pSpec); + glMaterialfv(GL_FRONT, GL_EMISSION, pEmis); + glMaterialf(GL_FRONT, GL_SHININESS, shiny); + + return 2; +} + +#if 0 +uint16 PFUNC_ZBIAS + uint16 offset /* To test if nearer - 0x8000 = reset. */ + uint16 units /* Integer units. not used. */ +#endif + +static int PrimFuncZBias(uint16* pData, Model* pMod, RState* pState) { + if(pData[1] & 0x8000) glDepthRange (pState->dn+SBRE_ZBIAS, pState->df); + else if(VecDot(pState->pVtx+pData[1], &pState->campos) > 0.0f) + glDepthRange(pState->dn, pState->df-SBRE_ZBIAS); + return 3; +} + +static int PrimFuncTriFlat(uint16* pData, Model* pMod, RState* pState) { + Vector* pVtx = pState->pVtx; + Vector* pVec; + Vector norm, tv1, tv2; + VecSub(pVtx+pData[1], pVtx+pData[2], &tv1); + VecSub(pVtx+pData[3], pVtx+pData[2], &tv2); + VecCross(&tv2, &tv1, &norm); + VecNorm(&norm, &norm); + + glBegin(GL_TRIANGLES); + glNormal3f(norm.x, norm.y, norm.z); + pVec = pVtx + pData[1]; + glVertex3f(pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[2]; + glVertex3f(pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[3]; + glVertex3f(pVec->x, pVec->y, pVec->z); + + if(pData[0] & RFLAG_XREF) { + glNormal3f(-norm.x, norm.y, norm.z); + pVec = pVtx + pData[3]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[2]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[1]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + } + glEnd(); + return 4; +} + +static int PrimFuncQuadFlat(uint16* pData, Model* pMod, RState* pState) { + Vector* pVtx = pState->pVtx; + Vector* pVec; + Vector norm, tv1, tv2; + VecSub(pVtx+pData[1], pVtx+pData[2], &tv1); + VecSub(pVtx+pData[3], pVtx+pData[2], &tv2); + VecCross(&tv2, &tv1, &norm); + VecNorm(&norm, &norm); + + glBegin(GL_TRIANGLE_FAN); + glNormal3f(norm.x, norm.y, norm.z); + pVec = pVtx + pData[1]; + glVertex3f(pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[2]; + glVertex3f(pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[3]; + glVertex3f(pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[4]; + glVertex3f(pVec->x, pVec->y, pVec->z); + glEnd(); + + if(pData[0] & RFLAG_XREF) { + glBegin(GL_TRIANGLE_FAN); + glNormal3f(-norm.x, norm.y, norm.z); + pVec = pVtx + pData[3]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[2]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[1]; + glVertex3f (-pVec->x, pVec->y, pVec->z); + pVec = pVtx + pData[4]; + glVertex3f(-pVec->x, pVec->y, pVec->z); + glEnd(); + } + return 5; +} + +void RenderArray(int nv, int ni, Vector* pVertex, uint16* pIndex, uint16 flags) { + glNormalPointer(GL_FLOAT, 2*sizeof(Vector), pVertex+1); + glVertexPointer(3, GL_FLOAT, 2*sizeof(Vector), pVertex); + glDrawElements(GL_TRIANGLES, ni, GL_UNSIGNED_SHORT, pIndex); + + if(flags & RFLAG_XREF) { + glPushMatrix(); + glFrontFace(GL_CCW); + const float pMV[16] = { -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + glMultMatrixf(pMV); + glDrawElements(GL_TRIANGLES, ni, GL_UNSIGNED_SHORT, pIndex); + glFrontFace(GL_CW); + glPopMatrix(); + } +} + +void CopyArrayToCache(int nv, int ni, Vector* pVertex, uint16* pIndex, int ci, Model* pModel) { + pModel->pNumIdx[ci] = ni; + pModel->pNumVtx[ci] = nv; + pModel->ppICache[ci] = (uint16 *) malloc (ni*sizeof(uint16)); + memcpy(pModel->ppICache[ci], pIndex, ni*sizeof(uint16)); + pModel->ppVCache[ci] = (Vector *) malloc (2*nv*sizeof(Vector)); + memcpy(pModel->ppVCache[ci], pVertex, 2*nv*sizeof(Vector)); +} + +#if 0 +uint16 PFUNC_COMPSMOOTH + uint16 cacheidx + uint16 steps + uint16 centpos + uint16 centnorm + uint16 startpos + uint16 startnorm + uint16 COMP_END + uint16 COMP_LINE + uint16 pos + uint16 norm + uint16 COMP_HERMITE + uint16 pos + uint16 norm + uint16 tan0 + uint16 tan1 + +/* Tangents should be prescaled. */ +#endif + +int PrimFuncCompoundSmooth(uint16* pData, Model* pMod, RState* pState) { + Vector *pVtx = pState->pVtx; + Model *pModel = pState->pModel; + + uint16 ci = pData[1]; + if(ci != 0x8000 && pModel->pNumIdx[ci]) { + RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci], + pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]); + int c; for(c=7; pData[c] != COMP_END; c+=pCompSize[pData[c]]); + return c+1; + } + + int steps = pData[2]; /* Detail factor... */ + Vector *pCPos = pVtx+pData[3]; + Vector *pCNorm = pVtx+pData[4]; /* Centre point. */ + Vector *pLPos = pVtx+pData[5]; + Vector *pLNorm = pVtx+pData[6]; + int c = 7; + + while(pData[c] != COMP_END) { + if(pData[c] == COMP_STEPS) steps = pData[c+1]; + else if(pData[c] == COMP_LINE) { + pLPos = pVtx+pData[c+1], pLNorm = pVtx+pData[c+2]; + TriangAddPoint (pLPos, pLNorm); + } else { + Vector t0, t1; + if(pData[c] == COMP_HERMITE) + { t0 = pVtx[pData[c+3]]; t1 = pVtx[pData[c+4]]; } + else if(pData[c] == COMP_HERM_NOTAN) + { VecSub (pVtx+pData[c+1], pLPos, &t0); t1 = t0; } + else if(pData[c] == COMP_HERM_AUTOTAN) { + Vector tv; VecSub (pVtx+pData[c+1], pLPos, &tv); + VecMul (pLNorm, VecDot (&tv, pLNorm), &t0); + VecSub (&tv, &t0, &t0); + VecMul (pVtx+pData[c+2], VecDot (&tv, pVtx+pData[c+2]), &t1); + VecSub (&tv, &t1, &t1); + } +// else { //crash? }; + + /* Now add points along spline. */ + float t, incstep = 1.0f / (steps+1); + int i; for(i=0, t=incstep; i uncacheable + uint16 steps 8 => octagonal + uint16 startvtx + uint16 endvtx + uint16 updir + uint16 rad +*/ + +static int PrimFuncCylinder(uint16* pData, Model* pMod, RState* pState) { + Vector* pVtx = pState->pVtx; + Model* pModel = pState->pModel; + + uint16 ci = pData[1]; + if(ci != 0x8000 && pModel->pNumIdx[ci]) { + RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci], + pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]); + return 7; + } + + int steps = pData[2]; + float rad = pData[6] * 0.01f; + Vector* pVertex = (Vector *) alloca (8*steps*sizeof(Vector)); + uint16* pIndex = (uint16 *) alloca (12*steps*sizeof(Vector)); + int ni = 0; + + /* Generate cylinder axes. */ + Vector yax = pVtx[pData[5]], xax, zax; + VecSub(pVtx+pData[4], pVtx+pData[3], &zax); // dir = end-start + VecNorm(&zax, &zax); + VecCross(&yax, &zax, &xax); + + float angstep = 2.0f * 3.141592f / steps, ang = 0.0f; + int i; for (i=0; i1; i--) { + pIndex[ni++] = steps*3; + pIndex[ni++] = i+steps*3; + pIndex[ni++] = i-1+steps*3; + } + + RenderArray(4*steps, ni, pVertex, pIndex, pData[0]); + if(ci != 0x8000) CopyArrayToCache(4*steps, ni, pVertex, pIndex, ci, pModel); + return 7; +} + +/* +uint16 PFUNC_CIRCLE + uint16 cacheidx -1 => uncacheable + uint16 steps 8 => octagonal + uint16 vtx + uint16 norm + uint16 updir + uint16 rad +*/ + +static int PrimFuncCircle(uint16* pData, Model* pMod, RState* pState) { + Vector* pVtx = pState->pVtx; + Model* pModel = pState->pModel; + + uint16 ci = pData[1]; + if(ci != 0x8000 && pModel->pNumIdx[ci]) { + RenderArray (pModel->pNumVtx[ci], pModel->pNumIdx[ci], + pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]); + return 7; + } + + int steps = pData[2]; + float rad = pData[6] * 0.01f; + Vector* pVertex = (Vector *) alloca (2*steps*sizeof(Vector)); + uint16* pIndex = (uint16 *) alloca (3*steps*sizeof(Vector)); + int ni = 0; + + /* Generate axes. */ + + Vector yax = pVtx[pData[5]], xax, zax = pVtx[pData[4]]; + VecCross(&yax, &zax, &xax); + + float angstep = 2.0f * 3.141592f / steps, ang = 0.0f; + int i; for(i=0; i uncacheable + uint16 steps 8 => octagonal + uint16 startvtx + uint16 endvtx + uint16 updir + uint16 outerrad + uint16 innerrad +*/ + +static int PrimFuncTube(uint16* pData, Model* pMod, RState* pState) { + Vector* pVtx = pState->pVtx; + Model* pModel = pState->pModel; + + uint16 ci = pData[1]; + if(ci != 0x8000 && pModel->pNumIdx[ci]) { + RenderArray(pModel->pNumVtx[ci], pModel->pNumIdx[ci], + pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]); + return 8; + } + + int steps = pData[2]; + Vector *pVertex = (Vector *) alloca (16*steps*sizeof(Vector)); + uint16 *pIndex = (uint16 *) alloca (24*steps*sizeof(Vector)); + int ni = 0; + + /* Generate cylinder axes. */ + Vector yax = pVtx[pData[5]], xax, zax; + VecSub(pVtx+pData[4], pVtx+pData[3], &zax); // dir = end-start + VecNorm(&zax, &zax); + VecCross(&yax, &zax, &xax); + +/* +0: start, outer, radial +steps: end, outer, radial +steps*2: start, inner, radial +steps*3: end, inner, radial +steps*4: start, outer, axial +steps*5: end, outer, axial +steps*6: start, inner, axial +steps*7: end, inner, axial +*/ + + float angstep = 2.0f * 3.141592f / steps, ang = 0.0f; + int i; for (i=0; ipObjParam->pFlag[pData[1]]) return 7; + + // build transform matrix, offset + Vector v1, v2, v3, pos; Matrix m, orient; + VecNorm (pState->pVtx+pData[4], &v2); + VecNorm (pState->pVtx+pData[5], &v3); + VecCross (&v2, &v3, &v1); + m.x1 = v1.x; m.x2 = v2.x; m.x3 = v3.x; + m.y1 = v1.y; m.y2 = v2.y; m.y3 = v3.y; + m.z1 = v1.z; m.z2 = v2.z; m.z3 = v3.z; + MatMatMult (&pState->objorient, &m, &orient); + + MatVecMult (&pState->objorient, pState->pVtx+pData[3], &pos); + VecAdd (&pos, &pState->objpos, &pos); + float scale = pState->scale*pData[6]*0.01f; + + glPushAttrib (GL_LIGHTING_BIT); + glPushMatrix (); + + /* Transform lin & ang thrust. */ + if(ppModel[pData[2]]->numThrusters) { + Vector compos; + MatTVecMult(&m, pState->pVtx+pData[3], &compos); + VecInv(&compos, &compos); + + ObjParams* pParam = pState->pObjParam; + Vector oldlin = *(Vector*)pParam->linthrust; + Vector oldang = *(Vector*)pParam->angthrust; + MatTVecMult(&m, &oldlin, (Vector*)pParam->linthrust); + MatTVecMult(&m, &oldang, (Vector*)pParam->angthrust); + + sbreRenderModel(&pos, &orient, pData[2], pParam, scale, &compos); + *(Vector*)pParam->linthrust = oldlin; + *(Vector*)pParam->angthrust = oldang; + } else sbreRenderModel (&pos, &orient, pData[2], pState->pObjParam, scale); + + glPopMatrix (); + glPopAttrib (); + return 7; +} + +static int glfinit = 0; +static FontFace *pFace = 0; + +/* +uint16 PFUNC_TEXT + uint16 anim + uint16 textnum + uint16 pos + uint16 norm + uint16 xaxis + uint16 xoff + uint16 yoff + uint16 scale +*/ + +static int PrimFuncText (uint16 *pData, Model *pMod, RState *pState) +{ + if (!glfinit) { + GLFTInit (); + pFace = new FontFace ("arial.ttf"); + glfinit = 1; + } + + // return immediately if object is not present +// if (pData[1] != 0x8000 && !pState->pObjParam->pFlag[pData[1]]) return 7; + + // build transform matrix, offset + Vector v1, v2, v3, pos, tv; Matrix m, m2; + VecNorm (pState->pVtx+pData[4], &v3); + VecNorm (pState->pVtx+pData[5], &v1); + VecInv (&v3, &v3); VecCross (&v3, &v1, &v2); + m.x1 = v1.x; m.x2 = v2.x; m.x3 = v3.x; + m.y1 = v1.y; m.y2 = v2.y; m.y3 = v3.y; + m.z1 = v1.z; m.z2 = v2.z; m.z3 = v3.z; + MatMatMult (&pState->objorient, &m, &m2); + + VecMul (&v1, pData[6]*0.01f, &tv); + VecMul (&v2, pData[7]*0.01f, &pos); + VecAdd (&pos, &tv, &tv); + VecAdd (pState->pVtx+pData[3], &tv, &tv); + MatVecMult (&pState->objorient, &tv, &pos); + VecAdd (&pos, &pState->objpos, &pos); + + float s = pState->scale*pData[8]*0.01f / pFace->GetHeight(); + glPushMatrix (); + + float pMV[16]; + pMV[0] = s*m2.x1; pMV[1] = s*m2.y1; pMV[2] = s*m2.z1; pMV[3] = 0.0f; + pMV[4] = s*m2.x2; pMV[5] = s*m2.y2; pMV[6] = s*m2.z2; pMV[7] = 0.0f; + pMV[8] = s*m2.x3; pMV[9] = s*m2.y3; pMV[10] = s*m2.z3; pMV[11] = 0.0f; + pMV[12] = pos.x; pMV[13] = pos.y; pMV[14] = pos.z; pMV[15] = 1.0f; + glLoadMatrixf (pMV); + + glFrontFace (GL_CCW); + glNormal3f (0.0f, 0.0f, -1.0f); +// glColor4f (1.0f, 1.0f, 1.0f, 1.0f); + + const char *pText; + if (pData[2] != 0x8000) pText = pModelString[pData[2]]; + else pText = pState->pObjParam->pText[pData[1]]; + pFace->RenderString(pText); + + glFrontFace (GL_CW); + glPopMatrix (); + return 9; +} + +/* +uint16 PFUNC_EXTRUSION + uint16 cacheidx -1 => uncacheable + uint16 count + uint16 startvtx + uint16 endvtx + uint16 updir + uint16 rad + uint16 firstvtx +*/ + +static int PrimFuncExtrusion (uint16 *pData, Model *pMod, RState *pState) +{ + Vector *pVtx = pState->pVtx; + Model *pModel = pState->pModel; + + uint16 ci = pData[1]; + if (ci != 0x8000 && pModel->pNumIdx[ci]) + { + glShadeModel (GL_FLAT); + RenderArray (pModel->pNumVtx[ci], pModel->pNumIdx[ci], + pModel->ppVCache[ci], pModel->ppICache[ci], pData[0]); + glShadeModel (GL_SMOOTH); + return 8; + } + + int steps = pData[2]; + float rad = pData[6] * 0.01f; + Vector *pVertex = (Vector *) alloca (8*steps*sizeof(Vector)); + uint16 *pIndex = (uint16 *) alloca (12*steps*sizeof(Vector)); + int ni = 0; + + // generate cylinder axes + + Vector yax = pVtx[pData[5]], xax, zax; + VecSub (pVtx+pData[4], pVtx+pData[3], &zax); // dir = end-start + VecNorm (&zax, &zax); + VecCross (&yax, &zax, &xax); + + int i; for (i=0; i1; i--) { + pIndex[ni++] = steps*3; + pIndex[ni++] = i+steps*3; + pIndex[ni++] = i-1+steps*3; + } + + RenderArray(4*steps, ni, pVertex, pIndex, pData[0]); + if(ci != 0x8000) CopyArrayToCache(4*steps, ni, pVertex, pIndex, ci, pModel); + return 8; +} + + + +/* +uint16 PFUNC_WINDOWS + uint16 + uint16 textnum + uint16 pos + uint16 norm + uint16 xaxis + uint16 xoff + uint16 yoff + uint16 scale +*/ + + +int (*pPrimFuncTable[])(uint16 *, Model *, RState *) = { + 0, // end + PrimFuncMatAnim, + PrimFuncMatFixed, + PrimFuncMatVar, + PrimFuncZBias, + PrimFuncTriFlat, + PrimFuncQuadFlat, + PrimFuncCompoundSmooth, // just uses steps = 0 + PrimFuncCompoundSmooth, + PrimFuncCircle, + PrimFuncCylinder, + PrimFuncTube, + PrimFuncSubObject, + PrimFuncText, + PrimFuncExtrusion, +}; + + diff --git a/src/sbre/sbre.h b/src/sbre/sbre.h new file mode 100644 index 0000000..51b4f64 --- /dev/null +++ b/src/sbre/sbre.h @@ -0,0 +1,39 @@ +#pragma once +#include "jjtypes.h" +#include "jjvector.h" + +enum animsrc { + ASRC_GEAR = 0, + ASRC_SECFRAC, + ASRC_MINFRAC, + ASRC_HOURFRAC, + ASRC_DAYFRAC, +}; + +enum animflag { + AFLAG_GEAR = 0, +}; + +struct ObjParams { + float pAnim[10]; + uint8 pFlag[10]; + + float linthrust[3]; /* 1.0 to -1.0 */ + float angthrust[3]; /* 1.0 to -1.0 */ + + struct { + float pDiff[3]; + float pSpec[3]; + float pEmis[3]; + float shiny; + } pColor [3]; + + char pText[3][256]; +}; + +void sbreSetViewport(int w, int h, int d, float zn, float zf, float dn, float df); +void sbreSetDirLight(float* pColor, float* pDir); +void sbreSetWireframe(int val); +void sbreRenderModel(Vector* pPos, Matrix* pOrient, int model, ObjParams* pParam, + float s=1.0f, Vector* pCompos=0); + diff --git a/src/sbre/sbre_anim.h b/src/sbre/sbre_anim.h new file mode 100644 index 0000000..f9e8ecf --- /dev/null +++ b/src/sbre/sbre_anim.h @@ -0,0 +1,35 @@ +#pragma once +#include "jjtypes.h" +#include "jjvector.h" +#include "sbre.h" +#include "sbre_int.h" + +enum animmod { + AMOD_CLIP = 0, /* Just clip result to 0-1. */ + AMOD_MOD1, /* fmod(1), then clip. */ + AMOD_REF, /* fmod(2), reflect around 1, then clip. */ +}; + +struct AnimFunc { + int src; + int mod; + float order0; + float order1; + float order2; + float order3; +}; + +enum animfunc { + AFUNC_GEAR = 0, + AFUNC_GFLAP, + AFUNC_THRUSTPULSE, + AFUNC_LIN4SEC, +}; + +const AnimFunc pAFunc[] = { + { ASRC_GEAR, AMOD_CLIP, -1.0f, 2.0f, 0.0f, 0.0f }, + { ASRC_GEAR, AMOD_CLIP, 0.0f, 2.0f, 0.0f, 0.0f }, + { ASRC_MINFRAC, AMOD_REF, 0.0f, 30.0f, 0.0f, 0.0f }, + { ASRC_MINFRAC, AMOD_MOD1, 0.0f, 15.0f, 0.0f, 0.0f }, +}; + diff --git a/src/sbre/sbre_int.h b/src/sbre/sbre_int.h new file mode 100644 index 0000000..a322180 --- /dev/null +++ b/src/sbre/sbre_int.h @@ -0,0 +1,145 @@ +#pragma once +#include "jjtypes.h" +#include "jjvector.h" +#include "sbre.h" + +/******************************************************************************/ + +enum vtxtype { + VTYPE_PLAIN = 0, + VTYPE_DIR, + VTYPE_CROSS, + VTYPE_NORM, + VTYPE_ANIMLIN, + VTYPE_ANIMCUBIC, + VTYPE_ANIMHERM, + VTYPE_ANIMROTATE, +}; + +struct PlainVertex { + uint32 type; + Vector pos; +}; + +struct CompoundVertex { + uint16 type; + uint16 pParam[5]; +}; + +/******************************************************************************/ + +struct Thruster { + uint16 pos; /* Index into vertices. */ + uint16 dir; + float power; +}; + +struct Light { + uint8 animcolor; + uint8 animpower; + uint16 vtx; + float power; + float pColor[3]; +}; + +struct Model { + float scale; + + int numPVtx; + PlainVertex* pPVtx; + + int cvStart; + int numCVtx; + CompoundVertex* pCVtx; + + int numLights; + Light* pLight; + + int numThrusters; + Thruster* pThruster; + + uint16* pData; + + int numCache; /* Number of cached primitives. */ + int* pNumVtx, *pNumIdx; + Vector** ppVCache; + uint16** ppICache; +}; + +extern Model* ppModel[]; + +/******************************************************************************/ + +#define TRIANG_MAXPOINTS 64 +#define TRIANG_MAXSTEPS 5 + +void ResolveLinearInterp(Vector* p0, Vector* p1, float t, Vector* pRes); +void ResolveQuadraticSpline(Vector* p0, Vector* p1, Vector* p2, float t, Vector* pRes); +void ResolveCubicSpline(Vector* p0, Vector* p1, Vector* p2, Vector* p3, float t, Vector* pRes); +void ResolveHermiteSpline(Vector* p0, Vector* p1, Vector* n0, Vector* n1, float t, Vector* pRes); +void ResolveHermiteNormal(Vector* p0, Vector* p1, Vector* n0, Vector* n1, float t, Vector* pRes); + +void TriangAddPoint(Vector* pPos, Vector* pNorm); +void Triangulate(Vector* pCPos, Vector* pCNorm, int steps, + Vector** ppVtx, int* pNV, uint16** ppIndex, int* pNI); + +/******************************************************************************/ + +struct RState { + Model* pModel; /* Original model. */ + Vector* pVtx; /* Transformed vertices. */ + Vector campos; /* Camera pos relative to model. */ + Vector objpos; /* Object pos relative to camera. */ + Matrix objorient; /* Object orient relative to camera. */ + float scale; /* Current GL modelview scale. */ + ObjParams* pObjParam; /* Dynamic object parameters. */ + float dn, df; /* Near/far depth range. */ + Vector compos; /* Object relative center of mass. */ +}; + +enum primtype { + PTYPE_END = 0, + PTYPE_MATANIM, + PTYPE_MATFIXED, + PTYPE_MATVAR, + PTYPE_ZBIAS, + PTYPE_TRIFLAT, + PTYPE_QUADFLAT, + PTYPE_COMPFLAT, + PTYPE_COMPSMOOTH, + PTYPE_CIRCLE, + PTYPE_CYLINDER, + PTYPE_TUBE, + PTYPE_SUBOBJECT, + PTYPE_TEXT, + PTYPE_EXTRUSION, +}; + +extern int (*pPrimFuncTable[])(uint16*, Model*, RState*); + +static const int RFLAG_XREF = 0x8000; + +static const int THRUST_XREF = 0x8000; +static const int THRUST_NOANG = 0x4000; + +static const float SBRE_ZBIAS = 0.00002f; +static const float SBRE_AMB = 0.3f; + +enum comptype { + COMP_END = 0, + COMP_LINE, + COMP_HERMITE, + COMP_HERM_NOTAN, + COMP_HERM_AUTOTAN, + COMP_STEPS, +}; + +const int pCompSize[] = { 1, 3, 5, 3, 3, 2 }; + +const char pModelString[1][256] = { + "IZRILGOOD", +}; + +void RenderTransparencies(RState* pState); +float ResolveAnim (ObjParams* pObjParam, uint16 type); + diff --git a/src/sbre/simtriang.cpp b/src/sbre/simtriang.cpp new file mode 100644 index 0000000..05d4e6d --- /dev/null +++ b/src/sbre/simtriang.cpp @@ -0,0 +1,155 @@ +#include +#include "jjtypes.h" +#include "sbre_int.h" + +void ResolveLinearInterp(Vector* p0, Vector* p1, float t, Vector* pRes) { + Vector tv; + VecSub(p1, p0, &tv); + VecMul(&tv, t, &tv); + VecAdd(&tv, p0, pRes); +} + +void ResolveQuadraticSpline(Vector* p0, Vector* p1, Vector* p2, float t, Vector* pRes) { + float invt = 1.0f - t; + Vector tv; + VecMul(p0, invt*invt, pRes); + VecMul(p1, 2.0f*t*invt, &tv); + VecAdd(&tv, pRes, pRes); + VecMul(p2, t*t, &tv); + VecAdd(&tv, pRes, pRes); +} + +void ResolveCubicSpline(Vector* p0, Vector* p1, Vector* p2, Vector* p3, float t, Vector* pRes) { + float invt = 1.0f - t; + Vector tv1, tv2, tv; + VecMul(p0, invt*invt*invt, &tv1); + VecMul(p3, t*t*t, &tv); + VecAdd(&tv, &tv1, &tv1); + VecMul(p1, 3.0f*t*invt*invt, &tv2); + VecMul(p2, 3.0f*t*t*invt, &tv); + VecAdd(&tv, &tv2, &tv2); + VecAdd(&tv1, &tv2, pRes); +} + +void ResolveHermiteSpline(Vector* p0, Vector* p1, Vector* n0, Vector* n1, float t, Vector* pRes) { + float t2 = t*t, t3 = t*t*t; + Vector tv1, tv2, tv; + VecMul(p0, 2*t3-3*t2+1, &tv1); + VecMul(n0, t3-2*t2+t, &tv); + VecAdd(&tv, &tv1, &tv1); + VecMul(p1, -2*t3+3*t2, &tv2); + VecMul(n1, t3-t2, &tv); + VecAdd(&tv, &tv2, &tv2); + VecAdd(&tv1, &tv2, pRes); +} + +void ResolveHermiteTangent(Vector* p0, Vector* p1, Vector* n0, Vector* n1, float t, Vector* pRes) { + float t2 = t*t; + Vector tv1, tv2, tv; + VecMul(p0, 6*t2-6*t, &tv1); + VecMul(n0, 3*t2-4*t+1, &tv); + VecAdd(&tv, &tv1, &tv1); + VecMul(p1, -6*t2+6*t, &tv2); + VecMul(n1, 3*t2-2*t, &tv); + VecAdd(&tv, &tv2, &tv2); + VecAdd(&tv1, &tv2, pRes); +} + +/******************************************************************************/ + +struct TriangPoint { + Vector pos; /* Base pos, norm. */ + Vector norm; + int num; /* Count of valid vertices. */ + uint16 pIndex[TRIANG_MAXSTEPS+1]; /* Index of each vertex, inside to outside. */ +}; + +static uint16 pIndex[6*TRIANG_MAXPOINTS*(TRIANG_MAXSTEPS+1)]; +static Vector pVertex[2*TRIANG_MAXPOINTS*(TRIANG_MAXSTEPS+1)]; + +static TriangPoint pPoint[TRIANG_MAXPOINTS]; +static int numPoints = 0; + + +void TriangAddPoint(Vector* pPos, Vector* pNorm) { + if(numPoints == TRIANG_MAXPOINTS) return; + TriangPoint *tp = pPoint + numPoints++; + tp->pos = *pPos; tp->norm = *pNorm; +} + +void Triangulate(Vector* pCPos, Vector* pCNorm, int steps, + Vector** ppVtx, int* pNV, uint16** ppIndex, int* pNI) { + /* + *Ok. For each point, find number of increments + * and generate intermediate values. + */ + int nv = 0, ni = 0; + int i; for(int i=0; ipos, &tv); + // float len = sqrt (VecDot (&tv, &tv)); + // VecCross (&pCur->norm, pCNorm, &tnorm); + // VecCross (pCNorm, &tv, &tnorm2); + // if (VecDot (&tnorm, &tnorm2) < 0.0f) VecInv (&tnorm, &tnorm); + + pVertex[nv] = pCur->pos; /* Add first vertex to array. */ + pVertex[nv+1] = pCur->norm; + pCur->pIndex[0] = nv>>1; nv+=2; + + Vector t0, t1; /*Find tangents. */ + VecMul(&pCur->norm, VecDot (&tv, &pCur->norm), &t0); + VecSub(&tv, &t0, &t0); + VecMul(pCNorm, VecDot (&tv, pCNorm), &t1); + VecSub(&tv, &t1, &t1); + + if(steps > TRIANG_MAXSTEPS) pCur->num = TRIANG_MAXSTEPS; + else pCur->num = steps; + static const float pInv[] = { 1.0f, 0.5f, 0.3333333f, 0.25f, 0.2f, + 0.1666667f, 0.1428571f, 0.125f, 0.1111111f, 0.1f }; + + float t, inc = pInv[pCur->num]; + int j; for(t=inc, j=1; j<=pCur->num; j++, t+=inc) { + ResolveHermiteSpline(&pCur->pos, pCPos, &t0, &t1, t, pVertex+nv); + // ResolveHermiteTangent(&pCur->pos, pCPos, &t0, &t1, t, &tv); + // VecCross(&tv, &tnorm, pVertex+nv+1); + ResolveLinearInterp (&pCur->norm, pCNorm, t, pVertex+nv+1); + pCur->pIndex[j] = nv>>1; nv+=2; + } + } + pVertex[nv] = *pCPos; /* Add centre vertex to array. */ + pVertex[nv+1] = *pCNorm; + int cindex = nv>>1; nv+=2; + + /* Now render each radial strip from the centre. */ + for(i=0; ipIndex[pCur->num]; + pIndex[ni++] = pNext->pIndex[pNext->num]; + + int vc = pCur->num, vn = pNext->num; + while(vc|vn) { + if(vc) { + pIndex[ni++] = pCur->pIndex[vc]; + pIndex[ni++] = pCur->pIndex[--vc]; + pIndex[ni++] = pNext->pIndex[vn]; + } + if(vn) { + pIndex[ni++] = pNext->pIndex[vn]; + pIndex[ni++] = pCur->pIndex[vc]; + pIndex[ni++] = pNext->pIndex[--vn]; + } + } + } + + // return data + *pNI = ni; *pNV = nv>>1; + *ppIndex = pIndex; + *ppVtx = pVertex; + + numPoints = 0; + return; +} + diff --git a/src/sbre/transp.cpp b/src/sbre/transp.cpp new file mode 100644 index 0000000..0adac36 --- /dev/null +++ b/src/sbre/transp.cpp @@ -0,0 +1,221 @@ +#include +#include +#include "sbre_int.h" + +static const int pNumIndex[3] = +{ (2*4+1*8)*3, (2*8+5*16)*3, (2*16+13*32)*3 }; + +static Vector pTVertex4pt[2*4+2]; +static Vector pTVertex8pt[6*8+2]; +static Vector pTVertex16pt[14*16+2]; + +static uint16 pTIndex4pt[(2*4+1*8)*3]; +static uint16 pTIndex8pt[(2*8+5*16)*3]; +static uint16 pTIndex16pt[(2*16+13*32)*3]; + +static Vector *ppTVertex[3] = +{ pTVertex4pt, pTVertex8pt, pTVertex16pt }; + +static uint16 *ppTIndex[3] = +{ pTIndex4pt, pTIndex8pt, pTIndex16pt }; + + +/* +static void MakeRotationalSolid(Vector* pPos, int n, int r, Vector* pRes) { + int i, j, k; + for (i=1; ix = sin(ang) * pPos->y; + pCur->y = cos(ang) * pPos->y; + pCur->z = pPos->z; + } + } + *pCur = pos0; pCur++; + *pCur = pos1; pCur++; +} +*/ + +static void GenerateThrusters(void) { + Vector pos0 = { 0.0f, 0.0f, 0.0f }; + Vector pos1 = { 0.0f, 0.0f, 1.0f }; + Vector tan0 = { 0.0f, 1.0f, 0.2f }; + Vector tan1 = { 0.0f, -0.2f, 1.0f }; + + int j, n; + for(j=0, n=4; j<3; j++, n<<=1) { + Vector* pCur = ppTVertex[j]; + float t, incstep = 1.0f / (n-1); + int i; for(i=0, t=incstep; ix = sin(ang) * pPos->y; + pCur->y = cos(ang) * pPos->y; + pCur->z = pPos->z; + } + } + *pCur = pos0; pCur++; + *pCur = pos1; pCur++; + + int ni=0, k; + uint16 *pIndex = ppTIndex[j]; + + for(k=0; kpModel->pThruster + index; + + Vector start, end, dir = *pDir; + VecMul(pPos, pState->scale, &start); + float power = -VecDot(&dir, (Vector*)pState->pObjParam->linthrust); + + if(!(pThruster->dir & THRUST_NOANG)) { + Vector angdir, *pAT = (Vector*)pState->pObjParam->angthrust, cpos; + VecAdd(&pState->compos, &start, &cpos); + VecCross(&cpos, &dir, &angdir); + // VecNorm(&angdir, &angdir); + float xp = angdir.x * pAT->x; + float yp = angdir.y * pAT->y; + float zp = angdir.z * pAT->z; + if(xp+yp+zp > 0) { + if(xp > yp && xp > zp && fabs(pAT->x) > power) power = fabs(pAT->x); + else if(yp > xp && yp > zp && fabs(pAT->y) > power) power = fabs(pAT->y); + else if(zp > xp && zp > yp && fabs(pAT->z) > power) power = fabs(pAT->z); + } + } + + if(power <= 0.001f) return; + power *= pState->scale; + float width = sqrt(power)*pThruster->power*0.6f; + float len = power*pThruster->power; + VecMul(&dir, len, &end); + VecAdd(&end, &start, &end); + + Vector v1, v2, pos; Matrix m, m2; + v1.x = dir.y; v1.y = dir.z; v1.z = dir.x; + VecCross(&v1, &dir, &v2); VecNorm(&v2, &v2); + VecCross(&v2, &dir, &v1); + m.x1 = v1.x; m.x2 = v2.x; m.x3 = dir.x; + m.y1 = v1.y; m.y2 = v2.y; m.y3 = dir.y; + m.z1 = v1.z; m.z2 = v2.z; m.z3 = dir.z; + MatMatMult(&pState->objorient, &m, &m2); + + MatVecMult(&pState->objorient, &start, &pos); + VecAdd(&pos, &pState->objpos, &pos); + + float pMV[16]; + pMV[ 0] = m2.x1; pMV[ 1] = m2.y1; pMV[ 2] = m2.z1; pMV[ 3] = 0.0f; + pMV[ 4] = m2.x2; pMV[ 5] = m2.y2; pMV[ 6] = m2.z2; pMV[ 7] = 0.0f; + pMV[ 8] = m2.x3; pMV[ 9] = m2.y3; pMV[10] = m2.z3; pMV[11] = 0.0f; + pMV[12] = pos.x; pMV[13] = pos.y; pMV[14] = pos.z; pMV[15] = 1.0f; + glPushMatrix(); + glLoadMatrixf(pMV); + + glScalef(width*0.5f, width*0.5f, len*0.666f); + glColor4f(0.0f, 0.4f, 1.0f, 0.6f); + glVertexPointer(3, GL_FLOAT, sizeof(Vector), pTVertex8pt); + glDrawElements(GL_TRIANGLES, pNumIndex[1], GL_UNSIGNED_SHORT, pTIndex8pt); + + glScalef(2.0f, 2.0f, 1.5f); + glColor4f(0.4f, 0.0f, 1.0f, 0.6f); + glVertexPointer(3, GL_FLOAT, sizeof(Vector), pTVertex8pt); + glDrawElements(GL_TRIANGLES, pNumIndex[1], GL_UNSIGNED_SHORT, pTIndex8pt); + + glPopMatrix(); + return; +} + +// Occlusion problems +static void RenderLight (RState* pState, int index) { + /* Light *pLight = pState->pModel->pLight + index; + + float *pColor = pLight->pColor; + if (pLight->animcolor != -1) pColor = pState->pObjParam->ppColor[pLight->animcolor]; + + float power = pLight->power; + if (pLight->animpower != -1) power *= pState->pObjParam->pAnim[pLight->animpower]; + + Vector xax, zax; + VecAdd (&pState->campos, pState->pVtx+pLight->vtx, &zax); + Vector yax = { pState->objorient.x2, pState->objorient.y2, pState->objorient.z2 }; + VecNorm (&zax, &zax); VecCross (&yax, &zax, &xax); + VecNorm (&xax, &xax); VecCross (&zax, &xax, &yax); +*/ +} + +struct TransElem { + Vector pos, dir; + Thruster* pThruster; + float dist; +}; + +inline void SWAP (TransElem* a, TransElem* b) { TransElem t = *a; *a = *b; *b = t; } + +static void QuickSort (TransElem* pA, int end) { + if(end <= 0) return; + float pivotval = pA[end].dist; + int i, j; for(i=0, j=0; i 1) QuickSort (pA, j-1); j++; + if(j < end) QuickSort (pA+j, end-j); +} + +static int thrustgen = 0; + +void RenderTransparencies (RState *pState) { + Vector* pVtx = pState->pVtx; + Model* pModel = pState->pModel; + + if(!thrustgen) GenerateThrusters(); + thrustgen = 1; + + int maxElem = pModel->numThrusters*2; + if(!maxElem) return; + TransElem *pList = (TransElem*)alloca(maxElem*sizeof(TransElem)); + + Vector tv; + int i, numElem = 0; + for(i=0; inumThrusters; i++) { + Thruster *pThruster = pModel->pThruster+i; + pList[numElem].pThruster = pThruster; + pList[numElem].pos = pVtx[pThruster->pos]; + pList[numElem].dir = pVtx[pThruster->dir&0xff]; + VecAdd(&pState->campos, &pList[numElem].pos, &tv); + pList[numElem].dist = VecDot(&tv, &tv); + + if(pThruster->dir & THRUST_XREF) { + pList[numElem+1] = pList[numElem]; + pList[numElem+1].pos.x = -pList[numElem].pos.x; + pList[numElem+1].dir.x = -pList[numElem].dir.x; + VecAdd(&pState->campos, &pList[numElem+1].pos, &tv); + pList[numElem+1].dist = VecDot(&tv, &tv); + numElem++; + } + numElem++; + } + + QuickSort(pList, numElem-1); + + // for(i=numElem-1; i>=0; i--) + for(i=0; i +#include +#include "libs.h" +#include "star_system.h" + +class Sector { +public: + Sector(int x, int y); + + int m_numSystems; + struct System { + std::string name; + vector3f p; + StarSystem::SBody::SubType primaryStarClass; + }; + std::vectorm_systems; + +private: + std::string GenName(MTRand& rand); +}; + diff --git a/src/sector_view.cpp b/src/sector_view.cpp new file mode 100644 index 0000000..fceac79 --- /dev/null +++ b/src/sector_view.cpp @@ -0,0 +1,199 @@ +#include "libs.h" +#include "gui.h" +#include "l3d.h" +#include "sector_view.h" +#include "sector.h" +#include "system_info_view.h" + +SectorView::SectorView(void) : GenericSystemView() { + SetTransparency(true); + m_px = m_py = 0.5; + m_rot_x = m_rot_z = 0; + m_secx = m_secy = 0; + m_selected = -1; + m_zoom = 1; + + m_infoLabel = new Gui::Label(""); + Add(m_infoLabel, 2, 2); + + Gui::ImageButton* ib = new Gui::ImageButton("icons/sectorview_f6_systeminfo.png"); + ib->onClick.connect(sigc::mem_fun(this, &SectorView::OnClickSystemInfo)); + ib->SetShortcut(SDLK_F6, KMOD_NONE); + m_rightButtonBar->Add(ib, 2, 2); + + m_zoomInButton = new Gui::ImageButton("icons/zoom_in_f7.png"); + m_zoomInButton->SetShortcut(SDLK_F7, KMOD_NONE); + m_rightButtonBar->Add(m_zoomInButton, 34, 2); + + m_zoomOutButton = new Gui::ImageButton("icons/zoom_out_f8.png"); + m_zoomOutButton->SetShortcut(SDLK_F8, KMOD_NONE); + m_rightButtonBar->Add(m_zoomOutButton, 66, 2); + + GLUquadricObj* qobj = gluNewQuadric(); + +/* + m_gluSphereDlist = glGenLists(1); + glNewList(m_gluSphereDlist, GL_COMPILE); + gluDisk(qobj, 0.0, 0.2, 32, 1); + glEndList(); +*/ + + m_gluDiskDlist = glGenLists(1); + glNewList(m_gluDiskDlist, GL_COMPILE); + gluDisk(qobj, 0.0, 0.2, 20, 1); + glEndList(); + + gluDeleteQuadric(qobj); +} + +SectorView::~SectorView(void) { + glDeleteLists(m_gluDiskDlist, 1); +} + +void SectorView::OnClickSystemInfo(void) { + L3D::SetView(L3D::system_info_view); +} + +bool SectorView::GetSelectedSystem(int* sector_x, int* sector_y, int* system_idx) { + *sector_x = m_secx; + *sector_y = m_secy; + *system_idx = m_selected; + return m_selected != -1; +} + +#define SEC_SIZE 8 +#define DRAW_RAD 2 + +#define FFRAC(_x) ((_x)-floor(_x)) + +void SectorView::Draw3D(void) { + GenericSystemView::Draw3D(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(50, L3D::GetScrAspect(), 1.0, 100.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + char buf[80]; + snprintf(buf, sizeof(buf), "Sector: %d,%d", m_secx, m_secy); + m_infoLabel->SetText(buf); + + /* Units are lightyears. */ + glTranslatef(0, 0, -10-10*m_zoom); + glRotatef(m_rot_x, 1, 0, 0); + glRotatef(m_rot_z, 0, 0, 1); + glTranslatef(-FFRAC(m_px)*SEC_SIZE, -FFRAC(m_py)*SEC_SIZE, 0); + glDisable(GL_LIGHTING); + + for(int sx = -DRAW_RAD; sx <= DRAW_RAD; sx++) { + for(int sy = -DRAW_RAD; sy <= DRAW_RAD; sy++) { + glPushMatrix(); + glTranslatef(sx*SEC_SIZE, sy*SEC_SIZE, 0); + DrawSector(m_secx+sx, m_secy+sy); + glPopMatrix(); + } + } + glEnable(GL_LIGHTING); +} + +void SectorView::PutText(std::string& text) { + /* Highly optimal.. */ + GLdouble modelMatrix[16]; + GLdouble projMatrix[16]; + GLint viewport[4]; + + glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); + glGetIntegerv(GL_VIEWPORT, viewport); + + Gui::Screen::EnterOrtho(); + vector3d _pos; + if(Gui::Screen::Project(0,0,0, modelMatrix, projMatrix, viewport, &_pos.x, &_pos.y, &_pos.z)) { + Gui::Screen::RenderLabel(text, _pos.x, _pos.y); + } + Gui::Screen::LeaveOrtho(); + glDisable(GL_LIGHTING); +} + +void SectorView::DrawSector(int sx, int sy) { + Sector s = Sector(sx, sy); + glColor3f(0, .8, 0); + glBegin(GL_LINE_LOOP); + glVertex3f(0, 0, 0); + glVertex3f(0, SEC_SIZE, 0); + glVertex3f(SEC_SIZE, SEC_SIZE, 0); + glVertex3f(SEC_SIZE, 0, 0); + glEnd(); + + if(!(sx || sy)) glColor3f(1, 1, 0); + int num = 0; + for(std::vector::iterator i = s.m_systems.begin(); i != s.m_systems.end(); ++i) { + glColor3fv(StarSystem::starColors[(*i).primaryStarClass]); + glPushMatrix(); + glTranslatef((*i).p.x*SEC_SIZE, (*i).p.y*SEC_SIZE, 0); + glBegin(GL_LINES); + glVertex3f(0, 0, 0); + glVertex3f(0, 0, (*i).p.z); + glEnd(); + glTranslatef(0, 0, (*i).p.z); + + glPushMatrix(); + glRotatef(-m_rot_z, 0, 0, 1); + glRotatef(-m_rot_x, 1, 0, 0); + glCallList(m_gluDiskDlist); + /* Selected indicator. */ + if((sx == m_secx) && (sy == m_secy) && (num == m_selected)) { + glColor3f(0, 0.8, 0); + glScalef(2, 2, 2); + glCallList(m_gluDiskDlist); + } + glPopMatrix(); + glColor3f(.7, .7, .7); + PutText((*i).name); + + glPopMatrix(); + num++; + } +} + +void SectorView::Update(void) { + if(L3D::KeyState(SDLK_LEFT)) m_px -= 0.01; + if(L3D::KeyState(SDLK_RIGHT)) m_px += 0.01; + if(L3D::KeyState(SDLK_UP)) m_py += 0.01; + if(L3D::KeyState(SDLK_DOWN)) m_py -= 0.01; + if(L3D::KeyState(SDLK_EQUALS)) m_zoom *= 0.99; + if(L3D::KeyState(SDLK_MINUS)) m_zoom *= 1.01; + if(m_zoomInButton->IsPressed()) m_zoom *= 0.99; + if(m_zoomOutButton->IsPressed()) m_zoom *= 1.01; + m_zoom = CLAMP(m_zoom, 0.1, 5.0); + + if(L3D::MouseButtonState(3)) { + int motion[2]; + L3D::GetMouseMotion(motion); + m_rot_x += motion[1]; + m_rot_z += motion[0]; + } + + m_secx = (int)floor(m_px); + m_secy = (int)floor(m_py); + + Sector s = Sector(m_secx, m_secy); + float px = FFRAC(m_px); + float py = FFRAC(m_py); + + m_selected = -1; + float min_dist = FLT_MAX; + for(unsigned int i = 0; i < s.m_systems.size(); i++) { + Sector::System* ss = &s.m_systems[i]; + float dx = px - ss->p.x; + float dy = py - ss->p.y; + float dist = sqrtf(dx*dx + dy*dy); + if(dist < min_dist) { + min_dist = dist; + m_selected = i; + } + } +} + diff --git a/src/sector_view.h b/src/sector_view.h new file mode 100644 index 0000000..e658236 --- /dev/null +++ b/src/sector_view.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include "libs.h" +#include "gui.h" +#include "view.h" +#include "generic_system_view.h" + +class SectorView : public GenericSystemView { +public: + SectorView(void); + virtual ~SectorView(void); + virtual void Update(void); + virtual void Draw3D(void); + bool GetSelectedSystem(int* sector_x, int* sector_y, int* system_idx); +private: + void DrawSector(int x, int y); + void PutText(std::string& text); + void OnClickSystemInfo(void); + + float m_zoom; + int m_secx, m_secy; + int m_selected; + float m_px, m_py; + float m_rot_x, m_rot_z; + Gui::Label* m_infoLabel; + Gui::ImageButton* m_zoomInButton; + Gui::ImageButton* m_zoomOutButton; + GLuint m_gluDiskDlist; +}; + + diff --git a/src/ship.cpp b/src/ship.cpp new file mode 100644 index 0000000..6526139 --- /dev/null +++ b/src/ship.cpp @@ -0,0 +1,140 @@ +#include "ship.h" +#include "objimport.h" +#include "frame.h" +#include "l3d.h" +#include "world_view.h" +#include "sbre/sbre.h" +#include "space.h" + +Ship::Ship(void) : RigidBody() { + m_dockedWith = 0; + m_mesh = 0; + m_shipType = ShipType::COBRA3; + m_angThrusters[0] = m_angThrusters[1] = m_angThrusters[2] = 0; + m_laserCollisionObj.owner = this; + for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) { + m_tempLaserGeom[i] = 0; + m_gunState[i] = 0; + } + dGeomSetData(m_geom, static_cast(this)); +} + +void Ship::SetThrusterState(enum ShipType::Thruster t, float level) { + m_thrusters[t] = level; +} + +void Ship::ClearThrusterState(void) { + for(int i = 0; i < ShipType::THRUSTER_MAX; i++) m_thrusters[i] = 0; +} + +void Ship::AITurn(void) { + const ShipType& stype = GetShipType(); + float timeStep = L3D::GetTimeStep(); + for(int i = 0; i < ShipType::THRUSTER_MAX; i++) { + float force = timeStep * stype.linThrust[i] * m_thrusters[i]; + switch(i) { + case ShipType::THRUSTER_REAR: + case ShipType::THRUSTER_FRONT: + dBodyAddRelForce(m_body, 0, 0, force); break; + case ShipType::THRUSTER_TOP: + case ShipType::THRUSTER_BOTTOM: + dBodyAddRelForce(m_body, 0, force, 0); break; + case ShipType::THRUSTER_LEFT: + case ShipType::THRUSTER_RIGHT: + dBodyAddRelForce(m_body, force, 0, 0); break; + } + } + dBodyAddRelTorque(m_body, stype.angThrust*m_angThrusters[0], + stype.angThrust*m_angThrusters[1], + stype.angThrust*m_angThrusters[2]); + + /* LASERZ!! */ + for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) { + /* Free old temp laser geoms. */ + if(m_tempLaserGeom[i]) dGeomDestroy(m_tempLaserGeom[i]); + m_tempLaserGeom[i] = 0; + if(!m_gunState[i]) continue; + dGeomID ray = dCreateRay(GetFrame()->GetSpaceID(), 10000); + const dReal* r = dGeomGetRotation(m_geom); + const vector3d pos = GetPosition(); + const vector3f _dir = stype.gunMount[i].dir; + vector3d dir = vector3d(_dir.x, _dir.y, _dir.z); + matrix4x4d m; + GetRotMatrix(m); + dir = m.ApplyRotationOnly(dir); + dGeomRaySet(ray, pos.x, pos.y, pos.z, dir.x, dir.y, dir.z); + dGeomSetData(ray, static_cast(&m_laserCollisionObj)); + m_tempLaserGeom[i] = ray; + } +} + +const ShipType& Ship::GetShipType(void) { + return ShipType::types[m_shipType]; +} + +void Ship::SetDockedWith(SpaceStation* s) { + if(m_dockedWith && !s) { + /* Launching. */ + printf("Buhbai!\n"); + m_dockedWith = 0; + vector3d pos = GetPosition(); + pos.x += 5000; + SetPosition(pos); + } else { + m_dockedWith = s; + SetVelocity(vector3d(0, 0, 0)); + SetAngVelocity(vector3d(0, 0, 0)); + } +} + +void Ship::SetMesh(ObjMesh* m) { + m_mesh = m; +} + +void Ship::SetGunState(int idx, int state) { + m_gunState[idx] = state; +} + +/* Assumed to be at model coords. */ +void Ship::RenderLaserfire(void) { + const ShipType& stype = GetShipType(); + glDisable(GL_LIGHTING); + for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) { + if(!m_gunState[i]) continue; + glColor3f(1, 0, 0); + glBegin(GL_LINES); + vector3f pos = stype.gunMount[i].pos; + glVertex3f(pos.x, pos.y, pos.z); + glVertex3fv(&((10000)*stype.gunMount[i].dir)[0]); + glEnd(); + } + glEnable(GL_LIGHTING); +} + +static ObjParams params = { + { 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f }, + + /* pColor[3] */ + { + { { 1.0f, 0.0f, 1.0f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, + { { 0.8f, 0.6f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, + { { 0.5f, 0.5f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 } + }, + /* pText[3][256] */ + { "IZ-L33T", "ME TOO" }, +}; + +void Ship::Render(const Frame* camFrame) { + params.angthrust[0] = m_angThrusters[0]; + params.angthrust[1] = m_angThrusters[1]; + params.angthrust[2] = m_angThrusters[2]; + params.linthrust[0] = m_thrusters[ShipType::THRUSTER_RIGHT] - m_thrusters[ShipType::THRUSTER_LEFT]; + params.linthrust[1] = m_thrusters[ShipType::THRUSTER_TOP] - m_thrusters[ShipType::THRUSTER_BOTTOM]; + params.linthrust[2] = m_thrusters[ShipType::THRUSTER_REAR] - m_thrusters[ShipType::THRUSTER_FRONT]; + strncpy(params.pText[0], GetLabel().c_str(), sizeof(params.pText)); + + RenderSbreModel(camFrame, 13, ¶ms); +} + diff --git a/src/ship_cpanel.cpp b/src/ship_cpanel.cpp new file mode 100644 index 0000000..20906a0 --- /dev/null +++ b/src/ship_cpanel.cpp @@ -0,0 +1,102 @@ +#include "libs.h" +#include "l3d.h" +#include "ship_cpanel.h" +#include "space_station_view.h" +#include "player.h" + +ShipCpanel::ShipCpanel(void) : Gui::Fixed(0, 0, 640, 64) { + //SetBgColor(1, 0, 0); + SetTransparency(true); + + Gui::Image* img = new Gui::Image("icons/cpanel.png"); + Add(img, 0, 0); + + Gui::RadioGroup* g = new Gui::RadioGroup(); + Gui::ImageRadioButton* b = new Gui::ImageRadioButton(g, "icons/timeaccel0.png", + "icons/timeaccel0_on.png"); + b->onSelect.connect(sigc::bind(sigc::mem_fun(this, &ShipCpanel::OnClickTimeaccel), 0.0)); + b->SetShortcut(SDLK_ESCAPE, KMOD_LSHIFT); + Add(b, 0, 26); + + b = new Gui::ImageRadioButton(g, "icons/timeaccel1.png", "icons/timeaccel1_on.png"); + b->onSelect.connect(sigc::bind(sigc::mem_fun(this, &ShipCpanel::OnClickTimeaccel), 1.0)); + b->SetShortcut(SDLK_F1, KMOD_LSHIFT); + b->SetSelected(true); + Add(b, 22, 26); + + b = new Gui::ImageRadioButton(g, "icons/timeaccel2.png", "icons/timeaccel2_on.png"); + b->onSelect.connect(sigc::bind(sigc::mem_fun(this, &ShipCpanel::OnClickTimeaccel), 10.0)); + b->SetShortcut(SDLK_F2, KMOD_LSHIFT); + Add(b, 44, 26); + + b = new Gui::ImageRadioButton(g, "icons/timeaccel3.png", "icons/timeaccel3_on.png"); + b->onSelect.connect(sigc::bind(sigc::mem_fun(this, &ShipCpanel::OnClickTimeaccel), 100.0)); + b->SetShortcut(SDLK_F3, KMOD_LSHIFT); + Add(b, 66, 26); + + b = new Gui::ImageRadioButton(g, "icons/timeaccel4.png", "icons/timeaccel4_on.png"); + b->onSelect.connect(sigc::bind(sigc::mem_fun(this, &ShipCpanel::OnClickTimeaccel), 1000.0)); + b->SetShortcut(SDLK_F4, KMOD_LSHIFT); + Add(b, 88, 26); + + g = new Gui::RadioGroup(); + Gui::MultiStateImageButton* cam_button = new Gui::MultiStateImageButton(); + g->Add(cam_button); + cam_button->SetSelected(true); + cam_button->AddState(L3D::CAM_FRONT, "icons/cam_front.png"); + cam_button->AddState(L3D::CAM_REAR, "icons/cam_rear.png"); + cam_button->AddState(L3D::CAM_EXTERNAL, "icons/cam_external.png"); + cam_button->SetShortcut(SDLK_F1, KMOD_NONE); + cam_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnChangeCamView)); + Add(cam_button, 2, 2); + + Gui::MultiStateImageButton* map_button = new Gui::MultiStateImageButton(); + g->Add(map_button); + map_button->SetSelected(false); + map_button->SetShortcut(SDLK_F2, KMOD_NONE); + map_button->AddState(L3D::MAP_SECTOR, "icons/cpan_f2_map.png"); + map_button->AddState(L3D::MAP_SYSTEM, "icons/cpan_f2_normal.png"); + map_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnChangeMapView)); + Add(map_button, 34, 2); + + Gui::ImageButton* comms_button = new Gui::ImageButton("icons/comms_f4.png"); + //g->Add(comms_button); + comms_button->SetShortcut(SDLK_F4, KMOD_NONE); + comms_button->onClick.connect(sigc::mem_fun(this, &ShipCpanel::OnClickComms)); + Add(comms_button, 98, 2); + + m_clock = new Gui::Label(""); + m_clock->SetColor(1, 0.7, 0); + Add(m_clock, 2, 48); +} + +void ShipCpanel::Draw(void) { + std::string time = date_format(L3D::GetGameTime()); + m_clock->SetText(time); + + Gui::Fixed::Draw(); + Remove(m_scannerWidget); +} + +void ShipCpanel::SetScannerWidget(Widget* w) { + m_scannerWidget = w; + Add(w, 150, 64); + w->Show(); +} + +void ShipCpanel::OnChangeCamView(Gui::MultiStateImageButton* b) { + L3D::SetCamType((enum L3D::CamType)b->GetState()); +} + +void ShipCpanel::OnChangeMapView(Gui::MultiStateImageButton* b) { + L3D::SetMapView((enum L3D::MapView)b->GetState()); +} + +void ShipCpanel::OnClickTimeaccel(Gui::ISelectable* i, double step) { + L3D::SetTimeStep(step); +} + +void ShipCpanel::OnClickComms(void) { + if(L3D::player->GetDockedWith()) L3D::SetView(L3D::spaceStationView); +} + diff --git a/src/ship_cpanel.h b/src/ship_cpanel.h new file mode 100644 index 0000000..b5fdf77 --- /dev/null +++ b/src/ship_cpanel.h @@ -0,0 +1,19 @@ +#pragma once +#include "libs.h" +#include "gui.h" + +class ShipCpanel : public Gui::Fixed { +public: + ShipCpanel(void); + virtual void Draw(void); + void SetScannerWidget(Widget* w); /* Must be done each frame. */ +private: + void OnChangeCamView(Gui::MultiStateImageButton* b); + void OnChangeMapView(Gui::MultiStateImageButton* b); + void OnClickTimeaccel(Gui::ISelectable* i, double step); + void OnClickComms(void); + + Widget* m_scannerWidget; + Gui::Label* m_clock; +}; + diff --git a/src/ship_type.cpp b/src/ship_type.cpp new file mode 100644 index 0000000..d316162 --- /dev/null +++ b/src/ship_type.cpp @@ -0,0 +1,13 @@ +#include "ship_type.h" + +const ShipType ShipType::types[1] = { + { + { 250, -250, 50, -50, -50, 50 }, + 500.0, + { + { vector3f(0, -0.5, 0), vector3f(0, 0, -1) }, + { vector3f(0, 0, 0), vector3f(0, 0, 1) } + } + } +}; + diff --git a/src/ship_type.h b/src/ship_type.h new file mode 100644 index 0000000..73a40de --- /dev/null +++ b/src/ship_type.h @@ -0,0 +1,23 @@ +#pragma once +#include "libs.h" +#include "vector3.h" + +struct ShipType { +public: + enum Thruster { THRUSTER_FRONT, THRUSTER_REAR, THRUSTER_TOP, THRUSTER_BOTTOM, + THRUSTER_LEFT, THRUSTER_RIGHT, THRUSTER_MAX }; + enum Type { COBRA3 }; + enum { GUNMOUNT_MAX = 2 }; + + /*******************************/ + float linThrust[THRUSTER_MAX]; + float angThrust; + struct GunMount { + vector3f pos; + vector3f dir; + } gunMount[GUNMOUNT_MAX]; + /*******************************/ + + static const ShipType types[1]; +}; + diff --git a/src/space.cpp b/src/space.cpp new file mode 100644 index 0000000..c651058 --- /dev/null +++ b/src/space.cpp @@ -0,0 +1,228 @@ +#include +#include +#include "libs.h" +#include "space.h" +#include "body.h" +#include "frame.h" +#include "star.h" +#include "planet.h" +#include "l3d.h" +#include "player.h" +#include "star_system.h" + +dWorldID Space::world; +std::list Space::bodies; +Frame* Space::rootFrame; +static dJointGroupID _contactgroup; + +void Space::Init(void) { + world = dWorldCreate(); + rootFrame = new Frame(NULL, "System"); + rootFrame->SetRadius(FLT_MAX); + _contactgroup = dJointGroupCreate(0); + //dWorldSetGravity(world, 0, -9.81, 0); +} + +void Space::Clear(void) { + for(std::list::iterator i = bodies.begin(); i != bodies.end(); ++i) { + (*i)->SetFrame(NULL); + if((*i) != (Body*)L3D::player) delete *i; + } + bodies.clear(); + /* Player now removed also, but not freed. */ + for(std::list::iterator i = rootFrame->m_children.begin(); + i != rootFrame->m_children.end(); ++i) delete *i; + rootFrame->m_children.clear(); + + L3D::player->SetFrame(rootFrame); + bodies.push_back(L3D::player); +} + +void Space::GenBody(StarSystem* system, StarSystem::SBody* sbody, Frame* f) { + Body* b; + if(sbody->type == StarSystem::SBody::TYPE_STAR) { + Star* star = new Star(sbody->subtype); + star->SetRadius(sbody->radius); + b = star; + } else { + Planet* planet = new Planet(sbody->subtype); + planet->SetRadius(sbody->radius); + b = planet; + } + b->SetLabel(sbody->name.c_str()); + + Frame* myframe; + + if(sbody->parent) { + myframe = new Frame(f, sbody->name.c_str()); + vector3d pos = sbody->orbit.CartesianPosAtTime(0); + myframe->SetPosition(pos); + myframe->SetRadius(10*sbody->radius); + b->SetFrame(myframe); + } else { + b->SetFrame(f); + myframe = f; + } + + b->SetPosition(vector3d(0, 0, 0)); + + AddBody(b); + + for(std::vector::iterator i = sbody->children.begin(); + i != sbody->children.end(); ++i) { + GenBody(system, *i, myframe); + } +} + +void Space::BuildSystem(StarSystem* system) { + GenBody(system, system->rootBody, rootFrame); +} + +void Space::AddBody(Body* b) { + bodies.push_back(b); +} + +void Space::UpdateFramesOfReference(void) { + for(std::list::iterator i = bodies.begin(); i != bodies.end(); ++i) { + Body* b = *i; + + if(!b->GetFlags() & Body::FLAG_CAN_MOVE_FRAME) continue; + + /* Falling out of frames. */ + if(!b->GetFrame()->IsLocalPosInFrame(b->GetPosition())) { + printf("%s leaves frame %s\n", b->GetLabel().c_str(), b->GetFrame()->GetLabel()); + + Frame* new_frame = b->GetFrame()->m_parent; + if(new_frame) { /* Don't fall out of root frame. */ + vector3d new_pos = b->GetPositionRelTo(new_frame); + b->SetFrame(new_frame); + b->SetPosition(new_pos); + } + } + + /* Entering into frames. */ + for(std::list::iterator j = b->GetFrame()->m_children.begin(); + j != b->GetFrame()->m_children.end(); ++j) { + Frame* kid = *j; + vector3d pos = b->GetFrame()->GetPosRelativeToOtherFrame(kid) + b->GetPosition(); + if(kid->IsLocalPosInFrame(pos)) { + printf("%s enters frame %s\n", b->GetLabel().c_str(), kid->GetLabel()); + b->SetPosition(pos); + b->SetFrame(kid); + break; + } + } + } +} + +static bool _OnCollision(dGeomID g1, dGeomID g2, Object* o1, Object* o2, + int numContacts, dContact contacts[]) { + if((o1->GetType() == Object::LASER) || (o2->GetType() == Object::LASER)) { + if(o1->GetType() == Object::LASER) { + std::swap(o1, o2); + std::swap(g1, g2); + } + Ship::LaserObj* lobj = static_cast(o2); + if(o1 == lobj->owner) return false; + printf("%s was shot by %s\n", ((Body*)o1)->GetLabel().c_str(), lobj->owner->GetLabel().c_str()); + if(o1->GetType() == Object::SHIP) { + RigidBody* rb = (RigidBody*)o1; + dVector3 start, dir; + dGeomRayGet(g2, start, dir); + dBodyAddForceAtPos(rb->m_body, + 100*dir[0], + 100*dir[1], + 100*dir[2], + contacts[0].geom.pos[0], + contacts[0].geom.pos[1], + contacts[0].geom.pos[2]); + } + return false; + } else { + Body* pb1 = static_cast(o1); + Body* pb2 = static_cast(o2); + if((pb1 && !pb1->OnCollision(pb2)) || (pb2 && !pb2->OnCollision(pb1))) return false; + } + return true; +} + +static void nearCallback(void* data, dGeomID oO, dGeomID o1) { + /* Create an array of dContact objects to hold the contact joints. */ + static const int MAX_CONTACTS = 10; + dContact contact[MAX_CONTACTS]; + + for(int i = 0; i < MAX_CONTACTS; i++) { + contact[i].surface.mode = dContactBounce | dContactSoftCFM; + contact[i].surface.mu = dInfinity; + contact[i].surface.mu2 = 0; + contact[i].surface.bounce = 0.8; + contact[i].surface.bounce_vel = 0.1; + contact[i].surface.soft_cfm = 0.01; + } + if(int numc = dCollide(oO, o1, MAX_CONTACTS, &contact[0].geom, sizeof(dContact))) { + Object* po1 = static_cast(dGeomGetData(oO)); + Object* po2 = static_cast(dGeomGetData(o1)); + if(!_OnCollision(oO, o1, po1, po2, numc, contact)) return; + /* Get the dynamics body for each geom. */ + dBodyID b1 = dGeomGetBody(oO); + dBodyID b2 = dGeomGetBody(o1); + /* + * To add contact point found to our joint group we call dJointCreateContact + * which is just one of the many different types available. + */ + for(int i = 0; i < numc; i++) { + /* + * dJointCreateContact needs to know which world and joint group to work + * with as well as the dContact object itself. + * It returns a new dJointID which we then use with dJointAttach to + * finally create the temp contact joint between the two geom bodies. + */ + dJointID c = dJointCreateContact(Space::world, _contactgroup, contact + i); + dJointAttach(c, b1, b2); + } + } +} + +void Space::CollideFrame(Frame* f) { + dSpaceCollide(f->GetSpaceID(), NULL, &nearCallback); + for(std::list::iterator i = f->m_children.begin(); i != f->m_children.end(); ++i) { + CollideFrame(*i); + } +} + +void Space::TimeStep(float step) { + CollideFrame(rootFrame); + //CollideFrame(L3D::player->GetFrame()); + dWorldQuickStep(world, step); + dJointGroupEmpty(_contactgroup); + + /* TODO: Does not need to be done this often. */ + UpdateFramesOfReference(); +} + +struct body_zsort_t { + double dist; + Body* b; +}; + +struct body_zsort_compare : public std::binary_function { + bool operator()(body_zsort_t a, body_zsort_t b) { return a.dist > b.dist; } +}; + +void Space::Render(const Frame* cam_frame) { + /* Simple z-sort. */ + body_zsort_t* bz = new body_zsort_t[bodies.size()]; + int idx = 0; + for(std::list::iterator i = bodies.begin(); i != bodies.end(); ++i) { + vector3d toBody = (*i)->GetPositionRelTo(cam_frame); + bz[idx].dist = toBody.Length(); + bz[idx].b = *i; + idx++; + } + sort(bz, bz+bodies.size(), body_zsort_compare()); + for(unsigned int i = 0; i < bodies.size(); i++) { + bz[i].b->Render(cam_frame); + } + delete [] bz; +} + diff --git a/src/space_station.cpp b/src/space_station.cpp new file mode 100644 index 0000000..6599696 --- /dev/null +++ b/src/space_station.cpp @@ -0,0 +1,55 @@ +#include "space_station.h" +#include "ship.h" +#include "objimport.h" + +SpaceStation::SpaceStation(void) : StaticRigidBody() { + dGeomSphereSetRadius(m_geom, 100.0); + dGeomSetData(m_geom, static_cast(this)); + matrix4x4d m = matrix4x4d::RotateYMatrix(M_PI); + dMatrix3 _m; + m.SaveToOdeMatrix(_m); + dGeomSetRotation(m_geom, _m); + m_mesh = 0; +} + +SpaceStation::~SpaceStation(void) { + //dGeomDestroy(m_geom); +} + +bool SpaceStation::OnCollision(Body* b) { + if(b->GetType() == Object::SHIP) { + Ship* s = static_cast(b); + if(!s->GetDockedWith()) { + s->SetDockedWith(this); + printf("docking!\n"); + } + return false; + } else { + return true; + } +} + +void SpaceStation::SetMesh(ObjMesh* m) { + m_mesh = m; +} + +static ObjParams params = { + { 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f }, + + /* pColor[3] */ + { + { { 1.0f, 0.0f, 1.0f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, + { { 0.8f, 0.6f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, + { { 0.5f, 0.5f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 } + }, + + /* pText[3][256] */ + { "Hello old bean", "CATZ!" }, +}; + +void SpaceStation::Render(const Frame* camFrame) { + RenderSbreModel(camFrame, 12, ¶ms); +} + diff --git a/src/space_station.h b/src/space_station.h new file mode 100644 index 0000000..fb66114 --- /dev/null +++ b/src/space_station.h @@ -0,0 +1,16 @@ +#pragma once +#include "libs.h" +#include "static_rigid_body.h" + +class SpaceStation : public StaticRigidBody { +public: + SpaceStation(void); + virtual ~SpaceStation(void); + virtual bool OnCollision(Body* b); + virtual Object::Type GetType(void) { return Object::SPACESTATION; } + virtual void Render(const Frame* camFrame); + void SetMesh(ObjMesh* m); +protected: + ObjMesh* m_mesh; +}; + diff --git a/src/space_station_view.cpp b/src/space_station_view.cpp new file mode 100644 index 0000000..e6ede4a --- /dev/null +++ b/src/space_station_view.cpp @@ -0,0 +1,47 @@ +#include "space_station_view.h" +#include "l3d.h" +#include "player.h" +#include "world_view.h" + +SpaceStationView::SpaceStationView(void) : View() { + SetTransparency(false); + + Gui::Label* l = new Gui::Label("Hello friend! Thankyou for docking with this space station!\n" + "You may have noticed that the docking procedure was not entirely\n" + "physically correct. this is a result of unimplemented physics in this\n" + "region of the galaxy. We hope to have things back to normal within a\n" + "few weeks, and in the mean time would like to offer our apologies for\n" + "any loss of earnings, immersion or lunch.\n\n" + "Currently the usual space station services are not available, but we\n" + "can offer you this promotional message from one of the station's sponsors:\n\n" + " ADOPT A CAT: THEY CHEW IMPORTANT CABLES!"); + + float size[2]; + GetSize(size); + Add(l, 40, size[1]-100); + + Gui::SolidButton* b = new Gui::SolidButton(); + b->onClick.connect(sigc::mem_fun(this, &SpaceStationView::OnClickRequestLaunch)); + Add(b, 40, size[1]-300); + l = new Gui::Label("Request Launch"); + Add(l, 65, size[1]-300); + + l = new Gui::Label("Comms Link"); + l->SetColor(1, .7, 0); + m_rightRegion2->Add(l, 10, 3); +} + +void SpaceStationView::OnClickRequestLaunch(void) { + printf("Launching!\n"); + L3D::player->SetDockedWith(0); + L3D::SetView(L3D::world_view); +} + +void SpaceStationView::Draw3D(void) { + +} + +void SpaceStationView::Update(void) { + +} + diff --git a/src/space_station_view.h b/src/space_station_view.h new file mode 100644 index 0000000..ef4e8b8 --- /dev/null +++ b/src/space_station_view.h @@ -0,0 +1,14 @@ +#pragma once +#include "libs.h" +#include "gui.h" +#include "view.h" + +class SpaceStationView : public View { +public: + SpaceStationView(void); + virtual void Update(void); + virtual void Draw3D(void); +private: + void OnClickRequestLaunch(void); +}; + diff --git a/src/star.cpp b/src/star.cpp new file mode 100644 index 0000000..4718ef1 --- /dev/null +++ b/src/star.cpp @@ -0,0 +1,52 @@ +#include "libs.h" +#include "star.h" + +Star::Star(StarSystem::SBody::SubType subtype): Body() { + m_subtype = subtype; + m_radius = 6378135.0; + m_pos = vector3d(0,0,0); +} + +vector3d Star::GetPosition(void) { + return m_pos; +} + +void Star::SetPosition(vector3d p) { + m_pos = p; +} + +void Star::TransformToModelCoords(const Frame* camFrame) { + vector3d fpos = GetPositionRelTo(camFrame); + glTranslatef(m_pos[0]+fpos.x, m_pos[1]+fpos.y, m_pos[2]+fpos.z); +} + +void Star::Render(const Frame* a_camFrame) { + static GLUquadricObj* qobj = NULL; + + if(!qobj) qobj = gluNewQuadric(); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glPushMatrix(); + + /* TODO duplicates code from Planet.cpp, not good. */ + double rad = m_radius; + vector3d fpos = GetPositionRelTo(a_camFrame); + double len = fpos.Length(); + + while(len > 1000.0f) { + rad *= 0.25; + fpos = 0.25*fpos; + len *= 0.25; + } + + glTranslatef(fpos.x, fpos.y, fpos.z); + + //TransformToModelCoords(a_camFrame); + glColor3fv(StarSystem::starColors[m_subtype]); + gluSphere(qobj, rad, 100, 100); + glPopMatrix(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); +} + diff --git a/src/star.h b/src/star.h new file mode 100644 index 0000000..59f5108 --- /dev/null +++ b/src/star.h @@ -0,0 +1,24 @@ +#pragma once +#include "body.h" +#include "star_system.h" + +class Frame; + +class Star: public Body { +public: + Star(StarSystem::SBody::SubType subtype); + virtual ~Star(void) { }; + virtual void SetPosition(vector3d p); + virtual vector3d GetPosition(void); + void SetRadius(double radius) { m_radius = radius; } + double GetRadius(void) { return m_radius; } + virtual void Render(const Frame* camFrame); + virtual void TransformToModelCoords(const Frame* camFrame); + virtual void TransformCameraTo(void) { }; + +private: + StarSystem::SBody::SubType m_subtype; + vector3d m_pos; + double m_radius; +}; + diff --git a/src/star_system.cpp b/src/star_system.cpp new file mode 100644 index 0000000..2a8242d --- /dev/null +++ b/src/star_system.cpp @@ -0,0 +1,453 @@ +#include "star_system.h" +#include "sector.h" + +#define CELSIUS 273.15 + +/* Indexed by enum subtype. */ +float StarSystem::starColors[7][3] = { + { 1.0, 0.2, 0.0 }, /* M */ + { 1.0, 0.6, 0.1 }, /* K */ + { 1.0, 1.0, 0.4 }, /* G */ + { 1.0, 1.0, 0.8 }, /* F */ + { 1.0, 1.0, 1.0 }, /* A */ + { 0.7, 0.7, 1.0 }, /* B */ + { 1.0, 0.7, 1.0 } /* O */ +}; + +static const struct SBodySubTypeInfo { + float mass; + float radius; + const char *description; + const char *icon; + float tempMin, tempMax; +} subTypeInfo[StarSystem::SBody::SUBTYPE_MAX] = { + { + 0.4, 0.5, "Type 'M' red star", + "icons/object_star_m.png", + 2000, 3500 + }, + { + 0.8, 0.9, "Type 'K' orange star", + "icons/object_star_k.png", + 3500, 5000 + }, + { + 1.1, 1.1, "Type 'G' yellow star", + "icons/object_star_g.png", + 5000, 6000 + }, + { + 1.7, 1.4, "Type 'F' white star", + "icons/object_star_f.png", + 6000, 7500 + }, + { + 3.1, 2.1, "Type 'A' hot white star", + "icons/object_star_a.png", + 7500, 10000 + }, + { + 18.0, 7.0, "Bright type 'B' blue star", + "icons/object_star_b.png", + 10000, 30000 + }, + { + 64.0, 16.0, "Hot, massive type 'O' blue star", + "icons/object_star_o.png", + 30000, 60000 + }, + { + 0, 0, "Brown dwarf sub-stellar object", + "icons/object_brown_dwarf.png" + }, + { + 0, 0, "Small gas giant", + "icons/object_planet_small_gas_giant.png" + }, + { + 0, 0, "Medium gas giant", + "icons/object_planet_medium_gas_giant.png" + }, + { + 0, 0, "Large gas giant", + "icons/object_planet_large_gas_giant.png" + }, + { + 0, 0, "Very large gas giant", + "icons/object_planet_large_gas_giant.png" + }, + { + 0, 0, "Small, rocky dwarf planet", + "icons/object_planet_dwarf.png" + }, + { + 0, 0, "Small, rocky planet with a thin atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with liquid water and a nitrogen atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with a carbon dioxide atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with a methane atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with running water and a thick nitrogen atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with a thick carbon dioxide atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Rocky planet with a thick methane atmosphere", + "icons/object_planet_small.png" + }, + { + 0, 0, "Highly volcanic world", + "icons/object_planet_small.png" + }, + { + 0, 0, "World with indigenous life and an oxygen atmosphere", + "icons/object_planet_life.png" + } +}; + +const char* StarSystem::SBody::GetAstroDescription(void) { + return subTypeInfo[subtype].description; +} + +const char* StarSystem::SBody::GetIcon(void) { + return subTypeInfo[subtype].icon; +} + +static const double boltzman_const = 5.6704e-8; + +static double calcEnergyPerUnitAreaAtDist(double star_radius, double star_temp, + double object_dist) { + + const double total_solar_emission = boltzman_const * pow(star_temp, 4) * + 4*M_PI*star_radius*star_radius; + + return total_solar_emission / (4*M_PI*object_dist*object_dist); +} + +/* Bond albedo, not geometric. */ +static double calcSurfaceTemp(double star_radius, double star_temp, + double object_dist, double albedo, + double greenhouse) { + + const double energy_per_meter2 = calcEnergyPerUnitAreaAtDist(star_radius, star_temp, + object_dist); + const double surface_temp = pow(energy_per_meter2*(1-albedo)/(4*(1-greenhouse)*boltzman_const), 0.25); + return surface_temp; +} + +void StarSystem::Orbit::KeplerPosAtTime(double t, double* dist, double* ang) { + double e = eccentricity; + double a = semiMajorAxis; + /* Mean anomaly. */ + double M = 2*M_PI*t / period; + /* Eccentic anomaly. */ + double E = M + (e - (1/8.0)*e*e*e)*sin(M) + + (1/2.0)*e*e*sin(2*M) + + (3/8.0)*e*e*e*sin(3*M); + /* True anomaly (angle of orbit position). */ + double v = 2*atan(sqrt((1+e)/(1-e)) * tan(E/2.0)); + /* Heliocentric distance. */ + double r = a * (1 - e*e) / (1 + e*cos(v)); + *ang = v; + *dist = r; +} + +vector3d StarSystem::Orbit::CartesianPosAtTime(double t) { + double dist, ang; + KeplerPosAtTime(t, &dist, &ang); + vector3d pos = vector3d(cos(ang)*dist, sin(ang)*dist, 0); + pos = rotMatrix * pos; + return pos; +} + +static std::vector* AccreteDisc(int size, float density, MTRand& rand) { + std::vector* disc = new std::vector(); + + for(int i = 0; i < size; i++) { + disc->push_back(density*rand(1.0)); + } + + for(int iter = 0; iter < 20; iter++) { + for(int i = 0; i < (signed)disc->size(); i++) { + for(int d = ceil(sqrtf((*disc)[i])+(i/5)); d > 0; d--) { + if((i+d < (signed)disc->size()) && ((*disc)[i] > (*disc)[i+d])) { + (*disc)[i] += (*disc)[i+d]; + (*disc)[i+d] = 0; + } + if(((i-d) >= 0) && ((*disc)[i] > (*disc)[i-d])) { + (*disc)[i] += (*disc)[i-d]; + (*disc)[i-d] = 0; + } + } + } + } + return disc; +} + +double calc_orbital_period(double semiMajorAxis, double centralMass) { + return 2.0*M_PI*sqrtf((semiMajorAxis*semiMajorAxis*semiMajorAxis)/(G*centralMass)); +} + +void StarSystem::SBody::EliminateBadChildren(void) { + /* Check for overlapping & unacceptably close orbits. Merge planets. */ + for (std::vector::iterator i = children.begin(); i != children.end(); ++i) { + if((*i)->temp) continue; + for(std::vector::iterator j = children.begin(); j != children.end(); ++j) { + if((*j) == (*i)) continue; + /* Don't eat anything bigger than self. */ + if((*j)->mass > (*i)->mass) continue; + double i_min = (*i)->radMin; + double i_max = (*i)->radMax; + double j_min = (*j)->radMin; + double j_max = (*j)->radMax; + bool eat = false; + if((*i)->orbit.semiMajorAxis > (*j)->orbit.semiMajorAxis) { + if(i_min < j_max*1.2) eat = true; + } else { + if(i_max > j_min*0.8) eat = true; + } + if(eat) { + (*i)->mass += (*j)->mass; + (*j)->temp = 1; + } + } + } + /* Kill the eaten ones. */ + for(std::vector::iterator i = children.begin(); i != children.end();) { + if((*i)->temp) { + i = children.erase(i); + } + else i++; + } +} + +StarSystem::StarSystem(int sector_x, int sector_y, int system_idx) { + unsigned long _init[3] = { system_idx, sector_x, sector_y }; + m_sectorX = sector_x; + m_sectorY = sector_y; + m_systemIdx = system_idx; + rootBody = 0; + if(system_idx == -1) return; + rand.seed(_init, 3); + + Sector s = Sector(sector_x, sector_y); + /* Primary. */ + SBody* primary = new SBody; + + StarSystem::SBody::SubType subtype = s.m_systems[system_idx].primaryStarClass; + primary->subtype = subtype; + primary->parent = NULL; + primary->radius = SOL_RADIUS*subTypeInfo[subtype].radius; + primary->mass = SOL_MASS*subTypeInfo[subtype].mass; + primary->type = SBody::TYPE_STAR; + primary->averageTemp = rand((int)subTypeInfo[subtype].tempMin, + (int)subTypeInfo[subtype].tempMax); + rootBody = primary; + + int disc_size = rand(6, 100) + rand(60,140)*primary->subtype*primary->subtype; + //printf("disc_size %.1fAU\n", disc_size/10.0); + + std::vector* disc = AccreteDisc(disc_size, 0.1+rand(1.5), rand); + for(unsigned int i = 0; i < disc->size(); i++) { + float mass = (*disc)[i]; + if(mass == 0) continue; + + SBody* planet = new SBody; + planet->subtype = SBody::SUBTYPE_PLANET_DWARF; + planet->temp = 0; + planet->parent = primary; + planet->radius = EARTH_RADIUS; + planet->mass = mass * EARTH_MASS; + planet->orbit.eccentricity = rand.pdrand(3); + planet->orbit.semiMajorAxis = ((i+1)*0.1)*AU; + planet->orbit.period = calc_orbital_period(planet->orbit.semiMajorAxis, primary->mass); + planet->orbit.rotMatrix = matrix4x4d::RotateYMatrix(rand.pdrand(5)*M_PI/2.0) * + matrix4x4d::RotateZMatrix(rand(M_PI)); + primary->children.push_back(planet); + + double ang; + planet->orbit.KeplerPosAtTime(0, &planet->radMin, &ang); + planet->orbit.KeplerPosAtTime(planet->orbit.period*0.5, &planet->radMax, &ang); + //printf(%f,%f\n", min/AU, max/AU); + //printf(%f year orbital period\n", planet->orbit.period / (60*60*24*365)); + } + delete disc; + + /* Merge children with overlapping or very close orbits. */ + primary->EliminateBadChildren(); + primary->name = s.m_systems[system_idx].name; + + int idx = 0; + for(std::vector::iterator i = primary->children.begin(); i != primary->children.end(); ++i) { + /* Turn them into... something! */ + char buf[3]; + buf[0] = ' '; + buf[1] = 'b'+(idx++); + buf[2] = 0; + (*i)->name = primary->name+buf; + double d = 0.5*((*i)->radMin + (*i)->radMax); + (*i)->L3DckPlanetType(primary, d, rand, true); + } +} + +void StarSystem::SBody::L3DckPlanetType(SBody* star, double distToPrimary, MTRand& rand, bool genMoons) { + float emass = mass / EARTH_MASS; + + /* Surface temperature. */ + /* https::/en.wikipedia.org/wiki/Black_body - Thanks again wiki. */ + const double d = distToPrimary; + double albedo = rand(0.5); + double globalwarming = rand(0.9); + /* Light planets have like.. no atmosphere. */ + if(emass < 1) globalwarming *= emass; + /* Big planets get high global warming owing to it's thick atmos. */ + if(emass > 3) globalwarming *= (emass-2.0f); + globalwarming = CLAMP(globalwarming, 0, 0.95); + + //printf("====\ndist %f, mass %f, albedo %f, globalwarming %f\n", d, emass, albedo, globalwarming); + + /* This is all of course a total joke and un-physical.. Sorry. */ + double bbody_temp; + bool fiddle = false; + for(int i = 0; i < 10; i++) { + bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, d, albedo, globalwarming); + //printf(temp %f, albedo %f, globalwarming %f\n", bbody_temp, albedo, globalwarming); + /* Extreme high temperature and low mass causes atmosphere loss. */ +#define ATMOS_LOSS_MASS_CUTOFF 2.0 +#define ATMOS_TEMP_CUTOFF 400 +#define FREEZE_TEMP_CUTOFF 220 + if((bbody_temp > ATMOS_TEMP_CUTOFF) && + (emass < ATMOS_LOSS_MASS_CUTOFF)) { + //printf("atmos loss\n"); + globalwarming = globalwarming * (emass/ATMOS_LOSS_MASS_CUTOFF); + fiddle = true; + } + if(!fiddle) break; + fiddle = false; + } + /* This is bs. Should decide atmosphere composition and then freeze out + * components of it in the previous loop. + */ + if((bbody_temp < FREEZE_TEMP_CUTOFF) && (emass < 5)) { + globalwarming *= 0.2; + albedo = rand(0.05) + 0.9; + } + bbody_temp = calcSurfaceTemp(star->radius, star->averageTemp, d, albedo, globalwarming); + // printf("= temp %f, albedo %f, globalwarming %f\n", bbody_temp, albedo, globalwarming); + + averageTemp = bbody_temp; + + if(emass > 317.8*13) { + /* More than 13 jupiter masses can fuse deuterium - is a brown dwarf. */ + subtype = SBody::SUBTYPE_BROWN_DWARF; + /* TODO Should prevent mass exceeding 65 jupiter masses or so, + * when it becomes a star. + */ + } else if(emass > 300) { + subtype = SBody::SUBTYPE_PLANET_LARGE_GAS_GIANT; + } else if(emass > 90) { + subtype = SBody::SUBTYPE_PLANET_MEDIUM_GAS_GIANT; + } else if(emass > 6) { + subtype = SBody::SUBTYPE_PLANET_SMALL_GAS_GIANT; + } else { + /* Terrestrial planets. */ + if(emass < 0.02) { + subtype = SBody::SUBTYPE_PLANET_DWARF; + } else if((emass < 0.2) && (globalwarming < 0.05)) { + subtype = SBody::SUBTYPE_PLANET_SMALL; + } else if(emass < 3) { + if((averageTemp > CELSIUS-10) && (averageTemp < CELSIUS+70)) { + /* Try for life.. */ + double minTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMax, albedo, globalwarming); + double maxTemp = calcSurfaceTemp(star->radius, star->averageTemp, radMin, albedo, globalwarming); + if((minTemp > CELSIUS-10) && (minTemp < CELSIUS+70) && + (maxTemp > CELSIUS-10) && (maxTemp < CELSIUS+70)) { + subtype = SBody::SUBTYPE_PLANET_INDIGENOUS_LIFE; + } else { + subtype = SBody::SUBTYPE_PLANET_WATER; + } + } else { + if(rand(0,1)) subtype = SBody::SUBTYPE_PLANET_CO2; + else subtype = SBody::SUBTYPE_PLANET_METHANE; + } + } else { /* 3 < emass < 6 */ + if((averageTemp > CELSIUS-10) && (averageTemp < CELSIUS+70)) { + subtype = SBody::SUBTYPE_PLANET_WATER_THICK_ATMOS; + } else { + if(rand(0,1)) subtype = SBody::SUBTYPE_PLANET_CO2_THICK_ATMOS; + else subtype = SBody::SUBTYPE_PLANET_METHANE_THICK_ATMOS; + } + } + /* Kinda crappy. */ + if((emass > 0.8) && (!rand(0,15))) subtype = SBody::SUBTYPE_PLANET_HIGHLY_VOLCANIC; + } + /* Generate moons. */ + if(genMoons) { + std::vector* disc = AccreteDisc(2*sqrt(emass), 0.001, rand); + for(unsigned int i = 0; i < disc->size(); i++) { + float mass = (*disc)[i]; + if(mass == 0) continue; + + SBody* moon = new SBody; + moon->subtype = SBody::SUBTYPE_PLANET_DWARF; + moon->temp = 0; + moon->parent = this; + moon->radius = EARTH_RADIUS; + moon->mass = mass * EARTH_MASS; + moon->orbit.eccentricity = rand.pdrand(3); + moon->orbit.semiMajorAxis = ((i+1)*0.001)*AU; + moon->orbit.period = calc_orbital_period(moon->orbit.semiMajorAxis, this->mass); + moon->orbit.rotMatrix = matrix4x4d::RotateYMatrix(rand.pdrand(5)*M_PI/2.0) * + matrix4x4d::RotateZMatrix(rand(M_PI)); + this->children.push_back(moon); + + double ang; + moon->orbit.KeplerPosAtTime(0, &moon->radMin, &ang); + moon->orbit.KeplerPosAtTime(moon->orbit.period*0.5, &moon->radMax, &ang); + //printf("%f,%f\n", min/AU, max/AU); + //printf("%f year orbital period\n", moon->orbit.period / (60*60*24*365)); + } + delete disc; + + /* Merge moons with overlapping or very close orbits. */ + EliminateBadChildren(); + + int idx = 0; + for(std::vector::iterator i = children.begin(); i != children.end(); ++i) { + /* Turn them into.. Something. */ + char buf[2]; + buf[0] = '1'+(idx++); + buf[1] = 0; + (*i)->name = name+buf; + (*i)->L3DckPlanetType(star, d, rand, false); + } + } +} + +StarSystem::~StarSystem(void) { + if(rootBody) delete rootBody; +} + +bool StarSystem::IsSystem(int sector_x, int sector_y, int system_idx) { + return (sector_x == m_sectorX) && (sector_y == m_sectorY) && (system_idx == m_systemIdx); +} + +StarSystem::SBody::~SBody(void) { + for(std::vector::iterator i = children.begin(); i != children.end(); ++i) { + delete (*i); + } +} + diff --git a/src/star_system.h b/src/star_system.h new file mode 100644 index 0000000..af14855 --- /dev/null +++ b/src/star_system.h @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include "libs.h" + +#define EARTH_RADIUS 6378135.0 +#define EARTH_MASS 5.9742e24 +#define JUPITER_MASS 317.8*EARTH_MASS +/* Brown dwarfs above 13 jupiter masses fuse deuterium. */ +#define MIN_BROWN_DWARF (13.0*JUPITER_MASS) +#define SOL_RADIUS 6.955e8 +#define SOL_MASS 1.98892e30 +#define AU 149598000000.0 +#define G 6.67428e-11 + +/* All masses are in Kg, all lengths in meters. */ +class StarSystem { +public: + StarSystem(int sector_x, int sector_y, int system_idx); + ~StarSystem(void); + bool IsSystem(int sector_x, int sector_y, int system_idx); + void GetPos(int* sec_x, int* sec_y, int* sys_idx) { + *sec_x = m_sectorX; *sec_y = m_sectorY; *sys_idx = m_systemIdx; + } + + static float starColors[7][3]; + + struct Orbit { + void KeplerPosAtTime(double t, double* dist, double* ang); + vector3d CartesianPosAtTime(double t); + double eccentricity; + double semiMajorAxis; + double period; /* Seconds. */ + matrix4x4d rotMatrix; + }; + + struct SBody { + ~SBody(void); + void EliminateBadChildren(void); /* :D */ + void L3DckPlanetType(SBody*, double distToPrimary, MTRand& drand, bool genMoons); + SBody* parent; + std::vector children; + Orbit orbit; + + const char* GetAstroDescription(void); + const char* GetIcon(void); + + int temp; + std::string name; + double radius; + double mass; + double radMin, radMax; + double averageTemp; + enum { TYPE_STAR, TYPE_ROCKY_PLANET, TYPE_GAS_GIANT } type; + + enum SubType { + SUBTYPE_STAR_M, + SUBTYPE_STAR_K, + SUBTYPE_STAR_G, + SUBTYPE_STAR_F, + SUBTYPE_STAR_A, + SUBTYPE_STAR_B, + SUBTYPE_STAR_O, + SUBTYPE_BROWN_DWARF, + SUBTYPE_PLANET_SMALL_GAS_GIANT, + SUBTYPE_PLANET_MEDIUM_GAS_GIANT, + SUBTYPE_PLANET_LARGE_GAS_GIANT, + SUBTYPE_PLANET_VERY_LARGE_GAS_GIANT, + SUBTYPE_PLANET_DWARF, + SUBTYPE_PLANET_SMALL, + SUBTYPE_PLANET_WATER, + SUBTYPE_PLANET_CO2, + SUBTYPE_PLANET_METHANE, + SUBTYPE_PLANET_WATER_THICK_ATMOS, + SUBTYPE_PLANET_CO2_THICK_ATMOS, + SUBTYPE_PLANET_METHANE_THICK_ATMOS, + SUBTYPE_PLANET_HIGHLY_VOLCANIC, + SUBTYPE_PLANET_INDIGENOUS_LIFE, + SUBTYPE_MAX + /* TODO: Need larger atmospherless things. */ + } subtype; + }; + + SBody* rootBody; + +private: + int m_sectorX, m_sectorY, m_systemIdx; + + MTRand rand; +}; + diff --git a/src/static_rigid_body.cpp b/src/static_rigid_body.cpp new file mode 100644 index 0000000..d100394 --- /dev/null +++ b/src/static_rigid_body.cpp @@ -0,0 +1,118 @@ +#include "libs.h" +#include "static_rigid_body.h" +#include "space.h" +#include "matrix4x4.h" +#include "frame.h" +#include "l3d.h" +#include "world_view.h" + +StaticRigidBody::StaticRigidBody(void): Body() { + m_geom = dCreateSphere(0, 50.0f); + dGeomSetBody(m_geom, 0); + SetPosition(vector3d(0,0,0)); +} + +StaticRigidBody::~StaticRigidBody(void) { + dGeomDestroy(m_geom); +} + +void StaticRigidBody::SetPosition(vector3d p) { + dGeomSetPosition(m_geom, p.x, p.y, p.z); +} + +void StaticRigidBody::SetVelocity(vector3d v) { + assert(0); +} + +vector3d StaticRigidBody::GetPosition(void) { + const dReal* pos = dGeomGetPosition(m_geom); + return vector3d(pos[0], pos[1], pos[2]); +} + +void StaticRigidBody::GetRotMatrix(matrix4x4d& m) { + m.LoadFromOdeMatrix(dGeomGetRotation(m_geom)); +} + +void StaticRigidBody::ViewingRotation(void) { + matrix4x4d m; + GetRotMatrix(m); + m = m.InverseOf(); + glMultMatrixd(&m[0]); +} + +void StaticRigidBody::TransformCameraTo(void) { + const dReal* p = dGeomGetPosition(m_geom); + matrix4x4d m; + GetRotMatrix(m); + m = m.InverseOf(); + glMultMatrixd(&m[0]); + glTranslated(-p[0], -p[1], -p[2]); +} + +void StaticRigidBody::TransformToModelCoords(const Frame* camFrame) { + vector3d fpos = GetPositionRelTo(camFrame); + + const dReal* r = dGeomGetRotation(m_geom); + matrix4x4d m; + m[ 0] = r[ 0]; m[ 1] = r[ 4]; m[ 2] = r[ 8]; m[ 3] = 0; + m[ 4] = r[ 1]; m[ 5] = r[ 5]; m[ 6] = r[ 9]; m[ 7] = 0; + m[ 8] = r[ 2]; m[ 9] = r[ 6]; m[10] = r[10]; m[11] = 0; + m[12] = fpos.x; m[13] = fpos.y; m[14] = fpos.z; m[15] = 1; + glMultMatrixd(&m[0]); +} + +void StaticRigidBody::SetFrame(Frame* f) { + if(GetFrame()) GetFrame()->RemoveGeom(m_geom); + Body::SetFrame(f); + if(f) f->AddGeom(m_geom); +} + +void StaticRigidBody::RenderSbreModel(const Frame* camFrame, int model, ObjParams* params) { + glPushMatrix(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + /* TODO Reduce. */ + glPushAttrib(GL_ALL_ATTRIB_BITS); + { + /* TODO Need to use correct starlight colour. */ + float lightCol[3] = { 1,1,1 }; + float lightDir[3]; + vector3d _lightDir = Frame::GetFramePosRelativeToOther(Space::GetRootFrame(), camFrame); + + matrix4x4d poo = L3D::world_view->viewingRotation; + poo[2] = -poo[2]; + poo[6] = -poo[6]; + poo[8] = -poo[8]; + poo[9] = -poo[9]; + _lightDir = poo*_lightDir; + + lightDir[0] = _lightDir.x; + lightDir[1] = _lightDir.y; + lightDir[2] = _lightDir.z; + + sbreSetDirLight(lightCol, lightDir); + } + + sbreSetViewport(L3D::GetScrWidth(), L3D::GetScrHeight(), L3D::GetScrWidth() + *0.5, 5.0f, 100000.0f, 0.0f, 1.0f); + vector3d pos = GetPositionRelTo(camFrame); + pos = L3D::world_view->viewingRotation*pos; + Vector p; p.x = pos.x; p.y = pos.y; p.z = -pos.z; + matrix4x4d rot; + rot.LoadFromOdeMatrix(dGeomGetRotation(m_geom)); + rot = L3D::world_view->viewingRotation * rot; + Matrix m; + m.x1 = rot[0]; m.x2 = rot[4]; m.x3 = -rot[8]; + m.y1 = rot[1]; m.y2 = rot[5]; m.y3 = -rot[9]; + m.z1 = -rot[2]; m.z2 = -rot[6]; m.z3 = rot[10]; + + sbreRenderModel(&p, &m, model, params); + + glPopAttrib(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + diff --git a/src/static_rigid_body.h b/src/static_rigid_body.h new file mode 100644 index 0000000..292ce18 --- /dev/null +++ b/src/static_rigid_body.h @@ -0,0 +1,29 @@ +#pragma once +#include "body.h" +#include "vector3.h" +#include "matrix4x4.h" +#include "sbre/sbre.h" + +class ObjMesh; + +class StaticRigidBody: public Body { +public: + StaticRigidBody(void); + virtual ~StaticRigidBody(void); + void SetPosition(vector3d p); + /* Not valid to do SetVelocity on these. They are for huge things like + * space stations and will be static relative to their frame of reference. + */ + void SetVelocity(vector3d v); + vector3d GetPosition(void); + void TransformToModelCoords(const Frame* camFrame); + void TransformCameraTo(void); + void ViewingRotation(void); + void GetRotMatrix(matrix4x4d& m); + virtual void SetFrame(Frame* f); + + void RenderSbreModel(const Frame* camFrame, int model, ObjParams* params); +protected: + dGeomID m_geom; +}; + diff --git a/src/system_info_view.cpp b/src/system_info_view.cpp new file mode 100644 index 0000000..190bca0 --- /dev/null +++ b/src/system_info_view.cpp @@ -0,0 +1,103 @@ +#include "l3d.h" +#include "sector.h" +#include "sector_view.h" +#include "system_info_view.h" +#include "ship_cpanel.h" + +SystemInfoView::SystemInfoView(void) : GenericSystemView() { + SetTransparency(true); + m_bodySelected = 0; + onSelectedSystemChanged.connect(sigc::mem_fun(this, &SystemInfoView::SystemChanged)); +} + +void SystemInfoView::OnBodySelected(StarSystem::SBody* b) { + m_bodySelected = b; + std::string desc; + char buf[1024]; + + snprintf(buf, sizeof(buf), "%s: %s\n" + "Mass %.2f Earth masses\n", + b->name.c_str(), b->GetAstroDescription(), b->mass/EARTH_MASS); + desc += buf; + + snprintf(buf, sizeof(buf), "Surface temperature %.0f C\n", b->averageTemp-273.15); + desc += buf; + + /* + * Surface temperature. + * Major starports. + * Orbital period. + * Orbiatal radius. + * ecc, incl. + */ + + if(b->parent) { + float days = b->orbit.period / (60*60*24); + if(days > 1000) { + snprintf(buf, sizeof(buf), "Orbital period %.1f years\n", days / 365); + } else { + snprintf(buf, sizeof(buf), "Orbital period %.1f days\n", b->orbit.period/(60*60*24)); + } + desc += buf; + snprintf(buf, sizeof(buf), "Perihelion distance %.2f AU\n", b->radMin / AU); + desc += buf; + snprintf(buf, sizeof(buf), "Aphelion distance %.2f AU\n", b->radMax / AU); + desc += buf; + snprintf(buf, sizeof(buf), "Eccentricity %.2f\n", b->orbit.eccentricity); + desc += buf; + } + m_infoText->SetText(desc); +} + +void SystemInfoView::SystemChanged(StarSystem* s) { + DeleteAllChildren(); + float csize[2]; + GetSize(csize); + + float xpos = 0; + float size[2]; + Gui::ImageButton* ib = new Gui::ImageButton(s->rootBody->GetIcon()); + ib->GetSize(size); + ib->onClick.connect(sigc::bind(sigc::mem_fun(this, &SystemInfoView::OnBodySelected), s->rootBody)); + Add(ib, 0, csize[1] - size[1]); + xpos += size[0]; + float ycent = csize[1] - size[1]*0.5; + + for(std::vector::iterator i = s->rootBody->children.begin(); + i != s->rootBody->children.end(); ++i) { + Gui::ImageButton* ib = new Gui::ImageButton((*i)->GetIcon()); + ib->GetSize(size); + ib->onClick.connect(sigc::bind(sigc::mem_fun(this, &SystemInfoView::OnBodySelected), *i)); + Add(ib, xpos, ycent - 0.5*size[1]); + + float moon_ypos = ycent - size[1] - 5; + if((*i)->children.size()) + for(std::vector::iterator moon = (*i)->children.begin(); + moon != (*i)->children.end(); ++moon) { + float msize[2]; + Gui::ImageButton* ib = new Gui::ImageButton((*moon)->GetIcon()); + ib->GetSize(msize); + ib->onClick.connect(sigc::bind(sigc::mem_fun(this, &SystemInfoView::OnBodySelected), *moon)); + Add(ib, xpos + 0.5*size[0] - 0.5*msize[0], moon_ypos); + moon_ypos -= msize[1]; + } + xpos += size[0]; + } + + char buf[512]; + snprintf(buf, sizeof(buf), "Stable system with %d major bodies.", 1+s->rootBody->children.size()); + m_infoText = new Gui::Label(buf); + m_infoText->SetColor(1, 1, 0); + Add(m_infoText, 50, 200); + + ShowAll(); +} + +void SystemInfoView::Draw3D(void) { + GenericSystemView::Draw3D(); +} + +void SystemInfoView::Update(void) { + +} + diff --git a/src/system_info_view.h b/src/system_info_view.h new file mode 100644 index 0000000..141c96e --- /dev/null +++ b/src/system_info_view.h @@ -0,0 +1,19 @@ +#pragma once +#include "libs.h" +#include "gui.h" +#include "view.h" +#include "star_system.h" +#include "generic_system_view.h" + +class SystemInfoView : public GenericSystemView { +public: + SystemInfoView(void); + virtual void Update(void); + virtual void Draw3D(void); +private: + void SystemChanged(StarSystem* s); + void OnBodySelected(StarSystem::SBody* b); + StarSystem::SBody* m_bodySelected; + Gui::Label* m_infoText; +}; + diff --git a/src/system_view.cpp b/src/system_view.cpp new file mode 100644 index 0000000..5ebf558 --- /dev/null +++ b/src/system_view.cpp @@ -0,0 +1,209 @@ +#include "system_view.h" +#include "l3d.h" +#include "sector_view.h" +#include "star_system.h" + +SystemView::SystemView(void): View() { + m_system = 0; + SetTransparency(true); + + m_timePoint = new Gui::Label(""); + m_timePoint->SetColor(.7, .7, .7); + Add(m_timePoint, 24, 5); + + m_zoomInButton = new Gui::ImageButton("icons/zoom_in_f7.png"); + m_zoomInButton->SetShortcut(SDLK_F7, KMOD_NONE); + m_rightButtonBar->Add(m_zoomInButton, 34, 2); + + m_zoomOutButton = new Gui::ImageButton("icons/zoom_out_f8.png"); + m_zoomOutButton->SetShortcut(SDLK_F8, KMOD_NONE); + m_rightButtonBar->Add(m_zoomOutButton, 66, 2); + + Gui::ImageButton* b = new Gui::ImageButton("icons/sysview_accel_r3.png", + "icons/sysview_accel_r3_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -10000000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 0, 0); + + b = new Gui::ImageButton("icons/sysview_accel_r2.png", + "icons/sysview_accel_r2_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -1000000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 26, 0); + + b = new Gui::ImageButton("icons/sysview_accel_r1.png", + "icons/sysview_accel_r1_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -100000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 45, 0); + + b = new Gui::ImageButton("icons/sysview_accel_f1.png", + "icons/sysview_accel_f1_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 100000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 64, 0); + + b = new Gui::ImageButton("icons/sysview_accel_f2.png", + "icons/sysview_accel_f2_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 1000000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 83, 0); + + b= new Gui::ImageButton("icons/sysview_accel_f3.png", + "icons/sysview_accel_f3_on.png"); + b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 10000000.0)); + b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0)); + m_rightRegion2->Add(b, 102, 0); + + ResetViewpoint(); +} + +SystemView::~SystemView(void) { + +} + +void SystemView::OnClickAccel(float step) { + m_timeStep = step; +} + +void SystemView::ResetViewpoint(void) { + m_selectedObject = 0; + m_rot_x = m_rot_z = 0; + m_zoom = 1.0f/AU; + m_timeStep = 1.0f; + m_time = L3D::GetGameTime(); +} + +void SystemView::PutOrbit(StarSystem::SBody* b) { + glColor3f(0, 1, 0); + glBegin(GL_LINE_LOOP); + double inc = b->orbit.period/100.0; + for(double t = 0.0; t < b->orbit.period; t += inc) { + vector3d pos = b->orbit.CartesianPosAtTime(t); + pos = pos * m_zoom; + glVertex3dv(&pos[0]); + } + glEnd(); +} + +void SystemView::OnClickObject(StarSystem::SBody* b, const Gui::MouseButtonEvent* ev) { + m_selectedObject = b; +} + +void SystemView::PutLabel(StarSystem::SBody* b) { + GLdouble modelMatrix[16]; + GLdouble projMatrix[16]; + GLint viewport[4]; + + glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix); + glGetDoublev (GL_PROJECTION_MATRIX, projMatrix); + glGetIntegerv(GL_VIEWPORT, viewport); + + Gui::Screen::EnterOrtho(); + + vector3d pos; + if(Gui::Screen::Project(0, 0, 0, modelMatrix, projMatrix, viewport, &pos[0], &pos[1], &pos[2])) { + /* libsigc++ is a lovely thing! */ + Gui::Screen::PutClickableLabel(b->name, pos.x, pos.y, + sigc::bind<0>(sigc::mem_fun(this, &SystemView::OnClickObject), b)); + } + + Gui::Screen::LeaveOrtho(); + glDisable(GL_LIGHTING); +} + +/* Yeah, I'm having trouble with a suitable name. :/ idc.*/ +#define ROUGH_SIZE_OF_THING 10.0 + +void SystemView::PutBody(StarSystem::SBody* b) { + glPointSize(5); + glColor3f(1,1,1); + glBegin(GL_POINTS); + glVertex3f(0,0,0); + glEnd(); + + PutLabel(b); + + if(b->children.size()) + for(std::vector::iterator kid = b->children.begin(); + kid != b->children.end(); ++kid) { + if((*kid)->orbit.semiMajorAxis * m_zoom < ROUGH_SIZE_OF_THING) + PutOrbit(*kid); + + glPushMatrix(); + { + /* Not using current time yet. */ + vector3d pos = (*kid)->orbit.CartesianPosAtTime(m_time); + pos = pos * m_zoom; + glTranslatef(pos.x, pos.y, pos.z); + PutBody(*kid); + } + glPopMatrix(); + } +} + +static const GLfloat fogDensity = 0.1; +static const GLfloat fogColor[4] = { 0, 0, 0, 1.0 }; + +void SystemView::ViewingTransformTo(StarSystem::SBody* b) { + if(b->parent) { + ViewingTransformTo(b->parent); + vector3d pos = b->orbit.CartesianPosAtTime(m_time); + pos = pos * m_zoom; + glTranslatef(-pos.x, -pos.y, -pos.z); + } +} + +void SystemView::Draw3D(void) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(50, L3D::GetScrAspect(), 1.0, 1000.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + int sector_x, sector_y, system_idx; + L3D::sector_view->GetSelectedSystem(§or_x, §or_y, &system_idx); + if(m_system) { + if(!m_system->IsSystem(sector_x, sector_y, system_idx)) { + delete m_system; + m_system = 0; + ResetViewpoint(); + } + } + m_time += m_timeStep*L3D::GetFrameTime(); + std::string t = "Time point: "+date_format(m_time); + m_timePoint->SetText(t); + + if(!m_system) m_system = new StarSystem(sector_x, sector_y, system_idx); + + glDisable(GL_LIGHTING); + glEnable(GL_FOG); + glFogi(GL_FOG_MODE, GL_EXP2); + glFogfv(GL_FOG_COLOR, fogColor); + glFogf(GL_FOG_DENSITY, fogDensity); + glHint(GL_FOG_HINT, GL_NICEST); + + glTranslatef(0, 0, -ROUGH_SIZE_OF_THING); + glRotatef(m_rot_x, 1, 0, 0); + glRotatef(m_rot_z, 0, 0, 1); + + if(m_selectedObject) ViewingTransformTo(m_selectedObject); + if(m_system->rootBody) PutBody(m_system->rootBody); + + glEnable(GL_LIGHTING); + glDisable(GL_FOG); +} + +void SystemView::Update(void) { + if(L3D::KeyState(SDLK_EQUALS) || + m_zoomInButton->IsPressed()) m_zoom *= 1.01; + if(L3D::KeyState(SDLK_MINUS) || + m_zoomOutButton->IsPressed()) m_zoom *= 0.99; + if(L3D::MouseButtonState(3)) { + int motion[2]; + L3D::GetMouseMotion(motion); + m_rot_x += motion[1]/4.0; + m_rot_z += motion[0]/4.0; + } +} + diff --git a/src/system_view.h b/src/system_view.h new file mode 100644 index 0000000..25d60b6 --- /dev/null +++ b/src/system_view.h @@ -0,0 +1,33 @@ +#pragma once +#include "libs.h" +#include "gui.h" +#include "view.h" +#include "star_system.h" + +class SystemView: public View { +public: + SystemView(void); + virtual ~SystemView(void); + virtual void Update(void); + virtual void Draw3D(void); + +private: + void PutOrbit(StarSystem::SBody* b); + void PutBody(StarSystem::SBody* b); + void PutLabel(StarSystem::SBody* b); + void ViewingTransformTo(StarSystem::SBody* b); + void OnClickObject(StarSystem::SBody* b, const Gui::MouseButtonEvent* ev); + void OnClickAccel(float step); + void ResetViewpoint(void); + + StarSystem* m_system; + StarSystem::SBody* m_selectedObject; + float m_rot_x, m_rot_z; + float m_zoom; + double m_time; + double m_timeStep; + Gui::ImageButton* m_zoomInButton; + Gui::ImageButton* m_zoomOutButton; + Gui::Label* m_timePoint; +}; + diff --git a/src/vector3.h b/src/vector3.h new file mode 100644 index 0000000..2a1d76f --- /dev/null +++ b/src/vector3.h @@ -0,0 +1,97 @@ +#pragma once +#include + +template +class vector3 { +public: + T x,y,z; + + vector3(void) { } + vector3(T val): x(val), y(val), z(val) { } + vector3(T _x, T _y, T _z): x(_x), y(_y), z(_z) { } + vector3(const T vals[3]): x(vals[0]), y(vals[1]), z(vals[2]) { } + + T& operator[] (const int i) { return ((T*)this)[i]; } + vector3 operator+ (const vector3 a) const { return vector3 (a.x+x, a.y+y, a.z+z); } + vector3& operator+= (const vector3 a) { x+=a.x; y+=a.y; z+=a.z; return *this; } + vector3& operator-= (const vector3 a) { x-=a.x; y-=a.y; z-=a.z; return *this; } + vector3& operator*= (const T a) { x*=a; y*=a; z*=a; return *this; } + vector3 operator- (const vector3 a) const { return vector3 (x-a.x, y-a.y, z-a.z); } + vector3 operator-(void) const { return vector3 (-x, -y, -z); } + bool operator==(const vector3 a) const { return ((a.x==x)&&(a.y==y)&&(a.z==z)); } + bool operator!=(const vector3 a) const { return ((a.x!=x)||(a.y!=y)||(a.z!=z)); } + friend vector3 operator*(const vector3 a, const vector3 b) { + return vector3 (a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } + friend vector3 operator*(const vector3 a, const T scalar) { + return vector3 (a.x*scalar, a.y*scalar, a.z*scalar); } + friend vector3 operator*(const T scalar, const vector3 a) { return a*scalar; } + + static vector3 Cross(const vector3 a, const vector3 b) { return a*b; } + static T Dot(const vector3 a, const vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } + + T Length(void) const { + return sqrt (x*x + y*y + z*z); + } + + void Normalize(void) { + T l = 1.0f / sqrtf(x*x + y*y + z*z); + x *= l; y *= l; z *= l; + } + + static vector3 Normalize(const vector3 v) { + vector3 r; + T l = 1.0f / sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + r.x = v.x * l; + r.y = v.y * l; + r.z = v.z * l; + return r; + } + + /* Rotate this vector about point o, in axis defined by v. */ + void ArbRotateAroundPoint(const vector3& o, const vector3& __v, T ang) { + vector3 t; + T a = o.x; + T b = o.y; + T c = o.z; + T u = __v.x; + T v = __v.y; + T w = __v.z; + T cos_a = cos(ang); + T sin_a = sin(ang); + T inv_poo = 1.0f/(u*u+v*v+w*w); + t.x = a*(v*v+w*w)+u*(-b*v-c*w+u*x+v*y+w*z)+(-a*(v*v+w*w)+u*(b*v+c*w-v*y-w*z)+(v*v+w*w)*x)*cos_a+ + sqrtf (u*u+v*v+w*w)*(-c*v+b*w-w*y+v*z)*sin_a; + t.x *= inv_poo; + t.y = b*(u*u+w*w)+v*(-a*u-c*w+u*x+v*y+w*z)+(-b*(u*u+w*w)+v*(a*u+c*w-u*x-w*z)+(u*u+w*w)*y)*cos_a+ + sqrtf (u*u+v*v+w*w)*(-c*u-a*w+w*x-u*z)*sin_a; + t.y *= inv_poo; + t.z = c*(u*u+v*v)+w*(-a*u+b*v+u*x+v*y+w*z)+(-c*(u*u+v*v)+w*(a*u+b*v-u*x-v*y)+(u*u+v*v)*z)*cos_a+ + sqrtf (u*u+v*v+w*w)*(-b*u+a*v-v*x+u*y)*sin_a; + t.z *= inv_poo; + *this = t; + } + /* Rotate this vector about origin, in axis defined by v. */ + void ArbRotate (const vector3 &__v, T ang) { + vector3 t; + T u = __v.x; + T v = __v.y; + T w = __v.z; + T cos_a = cos (ang); + T sin_a = sin (ang); + T inv_poo = 1.0f/(u*u+v*v+w*w); + t.x = u*(u*x+v*y+w*z)+(u*(-v*y-w*z)+(v*v+w*w)*x)*cos_a+ + sqrtf (u*u+v*v+w*w)*(-w*y+v*z)*sin_a; + t.x *= inv_poo; + t.y = v*(u*x+v*y+w*z)+(v*(-u*x-w*z)+(u*u+w*w)*y)*cos_a+ + sqrtf (u*u+v*v+w*w)*(w*x-u*z)*sin_a; + t.y *= inv_poo; + t.z = w*(u*x+v*y+w*z)+(w*(-u*x-v*y)+(u*u+v*v)*z)*cos_a+ + sqrtf (u*u+v*v+w*w)*(-v*x+u*y)*sin_a; + t.z *= inv_poo; + *this = t; + } +}; + +typedef vector3 vector3f; +typedef vector3 vector3d; + diff --git a/src/view.h b/src/view.h new file mode 100644 index 0000000..281aa6c --- /dev/null +++ b/src/view.h @@ -0,0 +1,42 @@ +#pragma once +#include "libs.h" +#include "gui.h" + +/* + * For whatever draws into the main area of the screen. + * Eg: + * Game 3D view. + * System map. + * Sector map. + */ + class View : public Gui::Fixed { + public: + View(void) : Gui::Fixed(0, 64, 640, 416) { + m_rightButtonBar = new Gui::Fixed(512, 0, 128, 26); + m_rightButtonBar->SetBgColor(.65, .65, .65); + + m_rightRegion2 = new Gui::Fixed(517, 26, 122, 17); + m_rightRegion2->SetTransparency(true); + } + virtual ~View(void) { delete m_rightButtonBar; delete m_rightRegion2; } + virtual void ShowAll(void) { + m_rightButtonBar->ShowAll(); + m_rightRegion2->ShowAll(); + Gui::Fixed::ShowAll(); + } + virtual void HideAll(void) { + m_rightButtonBar->HideAll(); + m_rightRegion2->HideAll(); + Gui::Fixed::HideAll(); + } + /* Called before Gui::Draw will call widget ::Draw methods. */ + virtual void Draw3D(void) = 0; + /* For checking key states, mouse stuff. */ + virtual void Update(void) = 0; +protected: + /* Each view can put some buttons in the bottom right of the cpanel. */ + Gui::Fixed* m_rightButtonBar; + //Gui::Fixed* m_rightRegion1; + Gui::Fixed* m_rightRegion2; + }; + diff --git a/src/world_view.cpp b/src/world_view.cpp new file mode 100644 index 0000000..0d413a8 --- /dev/null +++ b/src/world_view.cpp @@ -0,0 +1,103 @@ +#include "world_view.h" +#include "l3d.h" +#include "frame.h" +#include "player.h" +#include "space.h" + +static const float lightCol[] = { 1, 1, .9, 0 }; + +#define BG_STAR_MAX 2000 + +WorldView::WorldView(void): View() { + SetTransparency(true); + + m_hyperspaceButton = new Gui::ImageButton("icons/hyperspace_f8.png"); + m_hyperspaceButton->SetShortcut(SDLK_F8, KMOD_NONE); + m_hyperspaceButton->onClick.connect(sigc::mem_fun(this, &WorldView::OnClickHyperspace)); + m_rightButtonBar->Add(m_hyperspaceButton, 66, 2); + + m_bgstarsDlist = glGenLists(1); + + glNewList(m_bgstarsDlist, GL_COMPILE); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glPointSize(1.0); + glBegin(GL_POINTS); + for(int i = 0; i < BG_STAR_MAX; i++) { + float col = 0.2+L3D::rng(0.8); + glColor3f(col, col, col); + glVertex3f(1000-L3D::rng(2000.0), 1000-L3D::rng(2000.0), 1000-L3D::rng(2000.0)); + } + + glEnd(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + + glEndList(); +} + +void WorldView::OnClickHyperspace(void) { + StarSystem* s = L3D::GetSelectedSystem(); + if(s /* && isn's current system. */) { + printf("Traveling through hyperspace. WWEEEEEE!!\n"); + L3D::HyperspaceTo(s); + } +} + +void WorldView::Draw3D(void) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + /* Wth did I give these functions large names for.. :/ */ + glFrustum(-L3D::GetScrWidth()*.5, L3D::GetScrWidth()*.5, + -L3D::GetScrHeight()*.5, L3D::GetScrHeight()*.5, + L3D::GetScrWidth()*.5, 100000); + glDepthRange(-10, -100000); + glMatrixMode(GL_MODELVIEW); + + /* Make temporary camera frame at player. */ + Frame* cam_frame = new Frame(L3D::player->GetFrame(), "", Frame::TEMP_VIEWING); + + if(L3D::GetCamType() == L3D::CAM_FRONT) { + cam_frame->SetPosition(L3D::player->GetPosition()); + } else if(L3D::GetCamType() == L3D::CAM_REAR) { + glRotatef(180.0f, 0, 1, 0); + cam_frame->SetPosition(L3D::player->GetPosition()); + } else { /* CAM_EXTERNAL */ + cam_frame->SetPosition(L3D::player->GetPosition()); + L3D::player->ApplyExternalViewRotation(); + } + + L3D::player->ViewingRotation(); + + glGetDoublev(GL_MODELVIEW_MATRIX, &viewingRotation[0]); + + glCallList(m_bgstarsDlist); + /* Position light at sol. */ + vector3d lpos = Frame::GetFramePosRelativeToOther(Space::GetRootFrame(), cam_frame); + float lightPos[4]; + lightPos[0] = lpos.x; + lightPos[1] = lpos.y; + lightPos[2] = lpos.z; + lightPos[3] = 0; + glLightfv(GL_LIGHT0, GL_POSITION, lightPos); + glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, lightCol); + glLightfv(GL_LIGHT0, GL_SPECULAR, lightCol); + + Space::Render(cam_frame); + L3D::player->DrawHUD(cam_frame); + + L3D::player->GetFrame()->RemoveChild(cam_frame); + delete cam_frame; +} + +void WorldView::Update(void) { + if(L3D::GetSelectedSystem() /* && isn't current system */) { + m_hyperspaceButton->Show(); + } else { + m_hyperspaceButton->Hide(); + } + /* Player control inputs. */ + L3D::player->AITurn(); +} + diff --git a/src/world_view.h b/src/world_view.h new file mode 100644 index 0000000..77d86c8 --- /dev/null +++ b/src/world_view.h @@ -0,0 +1,18 @@ +#pragma once +#include "libs.h" +#include "gui.h" +#include "view.h" + +class WorldView: public View { +public: + WorldView(void); + virtual void Update(void); + virtual void Draw3D(void); + matrix4x4d viewingRotation; + +private: + void OnClickHyperspace(void); + Gui::ImageButton* m_hyperspaceButton; + GLuint m_bgstarsDlist; +}; +