diff --git a/sc2/src/uqm/gendef.c b/sc2/src/uqm/gendef.c index 6a0137762..a3cdf0770 100644 --- a/sc2/src/uqm/gendef.c +++ b/sc2/src/uqm/gendef.c @@ -51,11 +51,14 @@ extern GenerateFunctions generateYehatFunctions; extern GenerateFunctions generateZoqFotPikFunctions; extern GenerateFunctions generateZoqFotPikScoutFunctions; +extern GenerateFunctions *getGenerateCxxFunctions( void ); + const GenerateFunctions * -getGenerateFunctions (BYTE Index) +getGenerateFunctions (STAR_DESC *const star, void **sup ) { - switch (Index) + *sup= 0; + switch (star->Index) { case SOL_DEFINED: return &generateSolFunctions; @@ -132,6 +135,10 @@ getGenerateFunctions (BYTE Index) return &generateIlwrathFunctions; default: return &generateDefaultFunctions; + + case CXX_DEFINED: + *sup= star->supplement; + return getGenerateCxxFunctions(); } } diff --git a/sc2/src/uqm/gendef.h b/sc2/src/uqm/gendef.h index 41971f64d..8563d9875 100644 --- a/sc2/src/uqm/gendef.h +++ b/sc2/src/uqm/gendef.h @@ -8,7 +8,7 @@ extern "C" { #endif -const GenerateFunctions *getGenerateFunctions (BYTE Index); +const GenerateFunctions *getGenerateFunctions (STAR_DESC *star, void **sup); enum { @@ -60,7 +60,7 @@ enum ANDROSYNTH_DEFINED, MYCON_TRAP_DEFINED, - CUSTOM_DEFINED, + CXX_DEFINED, }; #define UMGAH_DEFINED TALKING_PET_DEFINED diff --git a/sc2/src/uqm/planets/generate-base.cpp b/sc2/src/uqm/planets/generate-base.cpp new file mode 100644 index 000000000..f899bf184 --- /dev/null +++ b/sc2/src/uqm/planets/generate-base.cpp @@ -0,0 +1,166 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "uqm/planets/generate.h" + +/* + * XXX: Note that the way that defaults get called via C++ is a bit + * indirect and wonky. The genFunc C table calls into the C++ + * wrappers which then call into the C++ object's vtable to these + * functions here... which then call back out to the C functions + * that would have been in the table. This does mean a bit more + * pointer chasing on each call... But I'm not really worried. + * + * Performance concerns aren't an issue as far as I'm concerned; + * after all -- Star Control 2 was a game that ran amazingly well + * on a 486 or Pentium. I played it just fine on a 90 MHz Pentium + * 1 with 32MiB of RAM (probably overkill on the RAM). My point + * is that a second layer of indirection and cache misses won't + * even be noticed, given how little this game should tax a + * modern CPU. + * + * As these functions are used to build a solar system, I think + * it only affects the "load time" for these systems -- and + * they're pretty easily loaded to begin with. And all of + * this indirection can go away once the planet handling at + * a higher level becomes C++ -- it can just call the vptrs + * directly. + * + * + * ===================================================================== + * + * Right now I need a lot of glue C++ to keep things all together, + * but once I can start to move more of the core program over + * to C++; I'll be able to let this glue fall away. This code is + * an example of that kind of glue. + */ + +namespace Planets ::detail:: Generate +{ + Generator::~Generator()= default; + + + // All of the default C++ generator functions forward to the + // plain C default impls. The idea is that you derive your + // special generator from the C++ one, just filling in the + // details you need. It _should_, in practice, clean up + // the boilerplate in the various `generate/genXXX` files. + // + // The `GenerateBindToCXX_XYZ` functions just forward to + // the C++ generator parameter in question. I still have + // to figure out where to store/parameterize that generator + // object. + // + // I think I'll just add an extra parameter to the function. + // + // That parameter will be a function pointer that returns + // a pointer to `Planets::detail::Generate::exports::Generator` + // in question. + + DefaultGenerator::~DefaultGenerator()= default; + + void + DefaultGenerator::initNpcs( SolarSystem *const solarSys ) + { + // This always returns true... + std::ignore= GenerateDefault_initNpcs( solarSys ); + } + + void + DefaultGenerator::reinitNpcs( SolarSystem *const solarSys ) + { + // This always returns true... + std::ignore= GenerateDefault_reinitNpcs( solarSys ); + } + + void + DefaultGenerator::uninitNpcs( SolarSystem *const solarSys ) + { + // This always returns true... + std::ignore= GenerateDefault_uninitNpcs( solarSys ); + } + + bool + DefaultGenerator::generatePlanets( SolarSystem *const solarSys ) + { + return GenerateDefault_generatePlanets( solarSys ); + } + + bool + DefaultGenerator::generateMoons( SolarSystem *const solarSys, PLANET_DESC *const planet ) + { + return GenerateDefault_generateMoons( solarSys, planet ); + } + + bool + DefaultGenerator::generateOrbital( SolarSystem *const solarSys, PLANET_DESC *const world ) + { + return GenerateDefault_generateOrbital( solarSys, world ); + } + + bool + DefaultGenerator::generateName( SolarSystem *const solarSys, PLANET_DESC *const world ) + { + return GenerateDefault_generateName( solarSys, world ); + } + + + COUNT + DefaultGenerator::generateMinerals( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode, NODE_INFO *const info ) + { + return GenerateDefault_generateMinerals( solarSys, world, whichNode, info ); + } + + + COUNT + DefaultGenerator::generateEnergy( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode, NODE_INFO *const info ) + { + return GenerateDefault_generateEnergy( solarSys, world, whichNode, info ); + } + + + COUNT + DefaultGenerator::generateLife( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode, NODE_INFO *const info ) + { + return GenerateDefault_generateLife( solarSys, world, whichNode, info ); + } + + bool + DefaultGenerator::pickupMinerals( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return GenerateDefault_pickupMinerals( solarSys, world, whichNode ); + } + + + bool + DefaultGenerator::pickupEnergy( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return GenerateDefault_pickupEnergy( solarSys, world, whichNode ); + } + + + bool + DefaultGenerator::pickupLife( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return GenerateDefault_pickupLife( solarSys, world, whichNode ); + } +} diff --git a/sc2/src/uqm/planets/generate.h b/sc2/src/uqm/planets/generate.h index 2b3bbb35f..5f9d1ece9 100644 --- a/sc2/src/uqm/planets/generate.h +++ b/sc2/src/uqm/planets/generate.h @@ -113,6 +113,91 @@ struct GenerateFunctions { }; #if defined(__cplusplus) +} // extern "C" + +namespace Planets ::detail:: Generate_m +{ + inline namespace exports + { + class Generator; + class DefaultGenerator; + + using SolarSystem= SOLARSYS_STATE; + } + + class exports::Generator + { + public: + virtual ~Generator()= 0; + + virtual void initNpcs( SolarSystem *solarSys )= 0; + virtual void reinitNpcs( SolarSystem *solarSys )= 0; + virtual void uninitNpcs( SolarSystem *solarSys )= 0; + virtual bool generatePlanets( SolarSystem *solarSys )= 0; + virtual bool generateMoons( SolarSystem *solarSys, + PLANET_DESC *planet )= 0; + virtual bool generateOrbital( SolarSystem *solarSys, + PLANET_DESC *world)= 0; + virtual bool generateName( const SolarSystem *, + const PLANET_DESC *world)= 0; + // The following functions return the number of objects being generated + // (or the index of the current object in some cases) + virtual COUNT generateMinerals( const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO * )= 0; + virtual COUNT generateEnergy( const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO * )= 0; + virtual COUNT generateLife( const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO * )= 0; + // The following functions return true if the node should be removed + // from the surface, i.e. picked up. + virtual bool pickupMinerals( SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode )= 0; + virtual bool pickupEnergy( SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode )= 0; + virtual bool pickupLife( SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode )= 0; + }; + + class exports::DefaultGenerator + : virtual public Generator + { + public: + ~DefaultGenerator() override; + + void initNpcs(SolarSystem *solarSys) override; + void reinitNpcs(SolarSystem *solarSys) override; + void uninitNpcs(SolarSystem *solarSys) override; + bool generatePlanets(SolarSystem *solarSys) override; + bool generateMoons(SolarSystem *solarSys, + PLANET_DESC *planet) override; + bool generateOrbital(SolarSystem *solarSys, + PLANET_DESC *world) override; + bool generateName(const SolarSystem *, + const PLANET_DESC *world) override; + + // The following functions return the number of objects being generated + // (or the index of the current object in some cases) + COUNT generateMinerals(const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO *) override; + COUNT generateEnergy(const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO *) override; + COUNT generateLife(const SolarSystem *, + const PLANET_DESC *world, COUNT whichNode, NODE_INFO *) override; + + // The following functions return true if the node should be removed + // from the surface, i.e. picked up. + bool pickupMinerals(SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode) override; + bool pickupEnergy(SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode) override; + bool pickupLife(SolarSystem *solarSys, + PLANET_DESC *world, COUNT whichNode) override; + }; +} + +namespace Planets::inline exports::inline Generate_m +{ + using namespace detail::Generate_m::exports; } #endif diff --git a/sc2/src/uqm/planets/generate/Makeinfo b/sc2/src/uqm/planets/generate/Makeinfo index 520af9d5a..bfa16f35e 100644 --- a/sc2/src/uqm/planets/generate/Makeinfo +++ b/sc2/src/uqm/planets/generate/Makeinfo @@ -4,3 +4,4 @@ uqm_CFILES="gendefault.c genand.c genburv.c genchmmr.c gencol.c gendru.c genthrad.c gentrap.c genutw.c genvault.c genvux.c genwreck.c genyeh.c genzfpscout.c genzoq.c" uqm_HFILES="genall.h gendefault.h" +uqm_CXXFILES="cxx-generator.cpp" diff --git a/sc2/src/uqm/planets/generate/cxx-generator.cpp b/sc2/src/uqm/planets/generate/cxx-generator.cpp new file mode 100644 index 000000000..15e15f0a5 --- /dev/null +++ b/sc2/src/uqm/planets/generate/cxx-generator.cpp @@ -0,0 +1,174 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "genall.h" +#include "../planets.h" +#include "../lander.h" +#include "../../encount.h" +#include "../../gamestr.h" +#include "../../globdata.h" +#include "../../grpinfo.h" +#include "../../races.h" +#include "../../state.h" +#include "../../sounds.h" +#include "libs/mathlib.h" + + +/* + * These bindings allow for the legacy C code to call into "GenerateFunctions" objects + * and have those calls mapped into the C++ virtual table driven object which handles + * the actual generation. + * + * This permits me to slowly migrate over the legacy C generators into C++. And to + * mess around with new C++-only generators. + * + * One nice advantage of this is that any C++ generator can inherit from another to + * specialize it. This permits `Default`ed forms to just use the base C++ defaulting + * class, using normal C++ `override` semantics. + * + * + * ===================================================================== + * + * Right now I need a lot of glue C++ to keep things all together, + * but once I can start to move more of the core program over + * to C++; I'll be able to let this glue fall away. This code is + * an example of that kind of glue. + */ + +namespace Planets ::detail:: CxxGeneratorBindings_m +{ + namespace + { + auto & + getGenerator( const SolarSystem *const solarSys ) + { + return *static_cast< Generator * >( solarSys->genSupplement ); + } + + bool + initNpcs( SolarSystem *const solarSys ) + { + getGenerator( solarSys ).initNpcs( solarSys ); + return true; + } + + bool + reinitNpcs( SolarSystem *const solarSys ) + { + getGenerator( solarSys ).reinitNpcs( solarSys ); + return true; + } + + bool + uninitNpcs( SolarSystem *const solarSys ) + { + getGenerator( solarSys ).uninitNpcs( solarSys ); + return true; + } + + bool + generatePlanets( SolarSystem *const solarSys ) + { + return getGenerator( solarSys ).generatePlanets( solarSys ); + } + + bool + generateMoons( SolarSystem *const solarSys, PLANET_DESC *const planet ) + { + return getGenerator( solarSys ).generateMoons( solarSys, planet ); + } + + bool + generateName( const SolarSystem *const solarSys, const PLANET_DESC *const world ) + { + return getGenerator( solarSys ).generateName( solarSys, world ); + } + + bool + generateOrbital( SolarSystem *const solarSys, PLANET_DESC *const world ) + { + return getGenerator( solarSys ).generateOrbital( solarSys, world ); + } + + COUNT + generateMinerals( const SolarSystem *const solarSys, + const PLANET_DESC *const world, const COUNT whichNode, NODE_INFO *const info ) + { + return getGenerator( solarSys ).generateMinerals( solarSys, world, whichNode, info ); + } + + bool + pickupMinerals( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return getGenerator( solarSys ).pickupMinerals( solarSys, world, whichNode ); + } + + COUNT + generateEnergy( const SolarSystem *const solarSys, + const PLANET_DESC *const world, const COUNT whichNode, + NODE_INFO *const info ) + { + return getGenerator( solarSys ).generateEnergy( solarSys, world, whichNode, info ); + } + + bool + pickupEnergy( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return getGenerator( solarSys ).pickupEnergy( solarSys, world, whichNode ); + } + + COUNT + generateLife( const SolarSystem *const solarSys, + const PLANET_DESC *const world, const COUNT whichNode, NODE_INFO *const info ) + { + return getGenerator( solarSys ).generateLife( solarSys, world, whichNode, info ); + } + + bool + pickupLife( SolarSystem *const solarSys, PLANET_DESC *const world, + const COUNT whichNode ) + { + return getGenerator( solarSys ).pickupLife( solarSys, world, whichNode ); + } + + const GenerateFunctions funcs = { + /* .initNpcs = */ initNpcs, + /* .reinitNpcs = */ reinitNpcs, + /* .uninitNpcs = */ uninitNpcs, + /* .generatePlanets = */ generatePlanets, + /* .generateMoons = */ generateMoons, + /* .generateName = */ generateName, + /* .generateOrbital = */ generateOrbital, + /* .generateMinerals = */ generateMinerals, + /* .generateEnergy = */ generateEnergy, + /* .generateLife = */ generateLife, + /* .pickupMinerals = */ pickupMinerals, + /* .pickupEnergy = */ pickupEnergy, + /* .pickupLife = */ pickupLife, + }; + } +} + +extern "C" +{ + const GenerateFunctions *getGenerateCxxFunctions( void ) + { + return &Planets::detail:: CxxGeneratorBindings_m::funcs; + } +} + diff --git a/sc2/src/uqm/planets/generate/cxx-generator.h b/sc2/src/uqm/planets/generate/cxx-generator.h new file mode 100644 index 000000000..0afba9df3 --- /dev/null +++ b/sc2/src/uqm/planets/generate/cxx-generator.h @@ -0,0 +1,35 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef GENDEFAULT_H +#define GENDEFAULT_H + +#include "types.h" +#include "../planets.h" +#include "libs/compiler.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const GenerateFunctions *getGenerateCxxFunctions(); + +#if defined(__cplusplus) +} +#endif + +#endif /* GENDEFAULT_H */ + diff --git a/sc2/src/uqm/planets/planets.h b/sc2/src/uqm/planets/planets.h index ab40caa66..56a62a692 100644 --- a/sc2/src/uqm/planets/planets.h +++ b/sc2/src/uqm/planets/planets.h @@ -130,6 +130,8 @@ struct star_desc BYTE Index; BYTE Prefix; BYTE Postfix; + + void *supplement; // The CXX builder's pointer gets put here. }; struct node_info @@ -249,6 +251,13 @@ struct solarsys_state BOOLEAN InOrbit; // Set to TRUE when player hits a world in an inner system // Homeworld encounters count as 'in orbit' + + // This points to the actual C++ generator type, for C++ + // implemented generators. + // + // Since everything else probably ignores it... we can probably + // avoid setting it to `nullptr`, for now... + void *genSupplement; }; extern SOLARSYS_STATE *pSolarSysState; diff --git a/sc2/src/uqm/planets/solarsys.c b/sc2/src/uqm/planets/solarsys.c index 930492d74..74213149b 100644 --- a/sc2/src/uqm/planets/solarsys.c +++ b/sc2/src/uqm/planets/solarsys.c @@ -1735,7 +1735,7 @@ ExploreSolarSys (void) memset (pSolarSysState, 0, sizeof (*pSolarSysState)); - SolarSysState.genFuncs = getGenerateFunctions (CurStarDescPtr->Index); + SolarSysState.genFuncs = getGenerateFunctions (CurStarDescPtr, &SolarSysState.genSupplement); InitSolarSys (); SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); diff --git a/sc2/src/uqm/uqmdebug.c b/sc2/src/uqm/uqmdebug.c index 6ed3da410..4fc540dd6 100644 --- a/sc2/src/uqm/uqmdebug.c +++ b/sc2/src/uqm/uqmdebug.c @@ -645,7 +645,7 @@ starRecurse (STAR_DESC *star, void *arg) SolarSysState.SunDesc[0].location.x = 0; SolarSysState.SunDesc[0].location.y = 0; //SolarSysState.SunDesc[0].radius = MIN_ZOOM_RADIUS; - SolarSysState.genFuncs = getGenerateFunctions (star->Index); + SolarSysState.genFuncs = getGenerateFunctions (star, &SolarSysState.genSupplement); pSolarSysState = &SolarSysState; (*SolarSysState.genFuncs->generatePlanets) (&SolarSysState);