Browse Source

LuaInvader sample: Replace direct OpenGL calls with calls to the render interface

Michael Ragazzon 3 years ago
parent
commit
aa8f30805b

+ 2 - 2
Samples/luainvaders/data/background.rml

@@ -8,7 +8,7 @@
 				z-index: -1;
 			}
 			
-			@decorator star : starfield {
+			@decorator stars : starfield {
 				num-layers: 5;
 				top-colour: #fffc;
 				bottom-colour: #fff3;
@@ -25,7 +25,7 @@
 				height: 100%;
 				z-index: 1;
 
-				decorator: star;
+				decorator: stars;
 			}
 		</style>
 	</head>

+ 17 - 26
Samples/luainvaders/src/DecoratorDefender.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,13 +28,12 @@
 
 #include "DecoratorDefender.h"
 #include <RmlUi/Core/Element.h>
-#include <RmlUi/Core/Texture.h>
+#include <RmlUi/Core/GeometryUtilities.h>
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/Texture.h>
 
-DecoratorDefender::~DecoratorDefender()
-{
-}
+DecoratorDefender::~DecoratorDefender() {}
 
 bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
@@ -66,27 +65,19 @@ void DecoratorDefender::RenderElement(Rml::Element* element, Rml::DecoratorDataH
 {
 	RMLUI_UNUSED(element_data);
 
-	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING).Round();
-	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING).Round();
+	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING);
+	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING);
+	Rml::Math::SnapToPixelGrid(position, size);
 
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) GetTexture(image_index)->GetHandle(element->GetRenderInterface()));
-	Rml::Colourb colour = element->GetProperty< Rml::Colourb >("color");
-	glColor4ubv(colour);
-	glBegin(GL_QUADS);
-
-		glVertex2f(position.x, position.y);
-		glTexCoord2f(0, 1);
-
-		glVertex2f(position.x, position.y + size.y);
-		glTexCoord2f(1, 1);
-
-		glVertex2f(position.x + size.x, position.y + size.y);
-		glTexCoord2f(1, 0);
+	if (Rml::RenderInterface* render_interface = element->GetRenderInterface())
+	{
+		Rml::TextureHandle texture = GetTexture(image_index)->GetHandle(render_interface);
+		Rml::Colourb color = element->GetProperty<Rml::Colourb>("color");
 
-		glVertex2f(position.x + size.x, position.y);
-		glTexCoord2f(0, 0);
+		Rml::Vertex vertices[4];
+		int indices[6];
+		Rml::GeometryUtilities::GenerateQuad(vertices, indices, Rml::Vector2f(0.f), size, color);
 
-	glEnd();
-	glColor4ub(255, 255, 255, 255);
+		render_interface->RenderGeometry(vertices, 4, indices, 6, texture, position);
+	}
 }

+ 36 - 24
Samples/luainvaders/src/DecoratorStarfield.cpp

@@ -27,14 +27,16 @@
  */
 
 #include "DecoratorStarfield.h"
-#include <RmlUi/Core/Math.h>
+#include "GameDetails.h"
+#include "Sprite.h"
+#include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/ElementUtilities.h>
+#include <RmlUi/Core/GeometryUtilities.h>
+#include <RmlUi/Core/Math.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/SystemInterface.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
-#include "GameDetails.h"
-
-float last_update_time = 0.0f;
 
 DecoratorStarfield::~DecoratorStarfield()
 {
@@ -56,8 +58,9 @@ bool DecoratorStarfield::Initialise(int _num_layers, const Rml::Colourb& _top_co
 /// Called on a decorator to generate any required per-element data for a newly decorated element.
 Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element) const
 {
-	StarField* star_field = new StarField();
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 
+	StarField* star_field = new StarField();
 	star_field->star_layers.resize(num_layers);
 
 	for (int i = 0; i < num_layers; i++)
@@ -84,51 +87,60 @@ Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* e
 			}
 		}
 
-		star_field->last_update = Shell::GetElapsedTime();
+		star_field->last_update = t;
 	}
 
-	return (Rml::DecoratorDataHandle)star_field;
+	return reinterpret_cast<Rml::DecoratorDataHandle>(star_field);
 }
 
 // Called to release element data generated by this decorator.
 void DecoratorStarfield::ReleaseElementData(Rml::DecoratorDataHandle element_data) const
 {
-	delete (StarField*)element_data;
+	delete reinterpret_cast<StarField*>(element_data);
 }
 
+
 // Called to render the decorator on an element.
 void DecoratorStarfield::RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const
 {
-	StarField* star_field = (StarField*)element_data;
-	star_field->Update();
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
+
+	StarField* star_field = reinterpret_cast<StarField*>(element_data);
+	star_field->Update(t);
 
 	const float dp_ratio = Rml::ElementUtilities::GetDensityIndependentPixelRatio(element);
 	const float point_size = Rml::Math::RoundUpFloat(2.f * dp_ratio);
 
-	glDisable(GL_TEXTURE_2D);
-	glPointSize(point_size);
-	glBegin(GL_POINTS);
+	Rml::RenderInterface* render_interface = element->GetRenderInterface();
+	if (!render_interface)
+		return;
+
+	int num_stars = 0;
+
+	for (size_t i = 0; i < star_field->star_layers.size(); i++)
+		num_stars += (int)star_field->star_layers[i].stars.size();
+
+	ColoredPointList points;
+	points.reserve(num_stars);
 
 	for (size_t i = 0; i < star_field->star_layers.size(); i++)
 	{
-		glColor4ubv(star_field->star_layers[i].colour);
-		
+		Rml::Colourb color = star_field->star_layers[i].colour;
+
 		for (size_t j = 0; j < star_field->star_layers[i].stars.size(); j++)
 		{
-			glVertex2f(star_field->star_layers[i].stars[j].x, star_field->star_layers[i].stars[j].y);
+			const Rml::Vector2f position = star_field->star_layers[i].stars[j];
+			points.push_back(ColoredPoint{color, position});
 		}
 	}
 
-	glEnd();
-
-	glColor4ub(255, 255, 255, 255);
+	DrawPoints(point_size, points);
 }
 
-void DecoratorStarfield::StarField::Update()
+void DecoratorStarfield::StarField::Update(double t)
 {
-	double time = Shell::GetElapsedTime();
-	float delta_time = float(time - last_update);
-	last_update = time;
+	float delta_time = float(t - last_update);
+	last_update = t;
 
 	if (!GameDetails::GetPaused())
 	{

+ 1 - 1
Samples/luainvaders/src/DecoratorStarfield.h

@@ -71,7 +71,7 @@ private:
 
 	struct StarField
 	{
-		void Update();
+		void Update(double t);
 		double last_update;
 		Rml::Vector2f dimensions;
 

+ 18 - 21
Samples/luainvaders/src/Defender.cpp

@@ -28,7 +28,6 @@
 
 #include "Defender.h"
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Game.h"
 #include "GameDetails.h"
 #include "Invader.h"
@@ -36,11 +35,11 @@
 #include "Shield.h"
 #include "Sprite.h"
 
-static const float UPDATE_FREQ = 0.01f;
-static const float MOVEMENT_SPEED = 300;
-static const float BULLET_SPEED = 15;
-static const int SPRITE_WIDTH = 64;
-static const float RESPAWN_TIME = 1.0f;
+const float UPDATE_FREQ = 0.01f;
+const float MOVEMENT_SPEED = 300;
+const float BULLET_SPEED = 15;
+const int SPRITE_WIDTH = 64;
+const float RESPAWN_TIME = 1.0f;
 
 Sprite defender_sprite(Rml::Vector2f(60, 31), Rml::Vector2f(0, 0.5), Rml::Vector2f(0.23437500, 0.98437500));
 Sprite bullet_sprite(Rml::Vector2f(4, 20), Rml::Vector2f(0.4921875, 0.515625), Rml::Vector2f(0.5078125, 0.828125));
@@ -63,15 +62,15 @@ Defender::~Defender()
 {
 }
 
-void Defender::Update()
+void Defender::Update(double t)
 {
-	float dt = float(Shell::GetElapsedTime() - defender_frame_start);
+	float dt = float(t - defender_frame_start);
 	if (dt < UPDATE_FREQ)
 		return;
-
-	dt = Rml::Math::Min(dt, 0.1f);
 	
-	defender_frame_start = Shell::GetElapsedTime();	
+	dt = Rml::Math::Min(dt, 0.1f);
+
+	defender_frame_start = t;	
 
 	position.x += (move_direction * dt * MOVEMENT_SPEED);
 
@@ -95,7 +94,7 @@ void Defender::Update()
 		render = !render;
 
 		// Check if we should switch back to our alive state
-		if (float(Shell::GetElapsedTime() - respawn_start) > RESPAWN_TIME)
+		if (float(t - respawn_start) > RESPAWN_TIME)
 		{
 			state = ALIVE;
 			render = true;
@@ -103,18 +102,18 @@ void Defender::Update()
 	}
 }
 
-void Defender::Render(float dp_ratio)
+void Defender::Render(double t, float dp_ratio, Rml::TextureHandle texture)
 {
-	glColor4ubv(GameDetails::GetDefenderColour());
+	Rml::Colourb color = GameDetails::GetDefenderColour();
 
 	// Render our sprite if rendering is enabled
 	if (render)
-		defender_sprite.Render(position, dp_ratio);
+		defender_sprite.Render(position, dp_ratio, color, texture);
 
 	// Update the bullet, doing collision detection
 	if (bullet_in_flight)
 	{
-		bullet_sprite.Render(bullet_position, dp_ratio);
+		bullet_sprite.Render(bullet_position, dp_ratio, color, texture);
 
 		// Check if we hit the shields
 		for (int i = 0; i < game->GetNumShields(); i++)
@@ -130,7 +129,7 @@ void Defender::Render(float dp_ratio)
 		{
 			for (int i = 0; i < game->GetNumInvaders(); i++)
 			{
-				if (game->GetInvader(i)->CheckHit(bullet_position))
+				if (game->GetInvader(i)->CheckHit(t, bullet_position))
 				{
 					bullet_in_flight = false;
 					break;
@@ -138,8 +137,6 @@ void Defender::Render(float dp_ratio)
 			}
 		}
 	}
-
-	glColor4ub(255, 255, 255, 255);
 }
 
 void Defender::StartMove(float direction)
@@ -163,7 +160,7 @@ void Defender::Fire()
 	}
 }
 
-bool Defender::CheckHit(const Rml::Vector2f& check_position)
+bool Defender::CheckHit(double t, const Rml::Vector2f& check_position)
 {	
 	float sprite_width = defender_sprite.dimensions.x;
 	float sprite_height = defender_sprite.dimensions.y;
@@ -178,7 +175,7 @@ bool Defender::CheckHit(const Rml::Vector2f& check_position)
 	{
 		game->RemoveLife();
 		state = RESPAWN;
-		respawn_start = Shell::GetElapsedTime();
+		respawn_start = t;
 
 		return true;
 	}	

+ 3 - 3
Samples/luainvaders/src/Defender.h

@@ -46,9 +46,9 @@ public:
 	~Defender();
 
 	/// Update the defender state.
-	void Update();
+	void Update(double t);
 	/// Render the defender.
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio, Rml::TextureHandle texture);
 
 	/// Move the defender left.
 	void StartMove(float direction);	
@@ -58,7 +58,7 @@ public:
 	void Fire();	
 
 	/// Check if an object at the given position would hit the defender.
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 private:
 	Game* game;

+ 7 - 5
Samples/luainvaders/src/ElementGame.cpp

@@ -27,12 +27,14 @@
  */
 
 #include "ElementGame.h"
+#include "Defender.h"
+#include "Game.h"
 #include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/ElementDocument.h>
-#include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Factory.h>
-#include "Defender.h"
-#include "Game.h"
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
 
 ElementGame::ElementGame(const Rml::String& tag) : Rml::Element(tag)
 {
@@ -81,7 +83,7 @@ void ElementGame::ProcessEvent(Rml::Event& event)
 // Updates the game.
 void ElementGame::OnUpdate()
 {
-	game->Update();
+	game->Update(Rml::GetSystemInterface()->GetElapsedTime());
 
 	if (game->IsGameOver())
 		DispatchEvent("gameover", Rml::Dictionary());
@@ -90,7 +92,7 @@ void ElementGame::OnUpdate()
 // Renders the game.
 void ElementGame::OnRender()
 {
-	game->Render(GetContext()->GetDensityIndependentPixelRatio());
+	game->Render(Rml::GetSystemInterface()->GetElapsedTime(), GetContext()->GetDensityIndependentPixelRatio());
 }
 
 void ElementGame::OnChildAdd(Rml::Element* element)

+ 8 - 20
Samples/luainvaders/src/Game.cpp

@@ -29,7 +29,6 @@
 #include "Game.h"
 #include <RmlUi/Core.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "GameDetails.h"
 #include "HighScores.h"
@@ -117,7 +116,7 @@ void Game::Initialise()
 	InitialiseWave();
 }
 
-void Game::Update()
+void Game::Update(double t)
 {
 	if (!GameDetails::GetPaused())
 	{
@@ -125,46 +124,35 @@ void Game::Update()
 			return;
 
 		// Determine if we should advance the invaders
-		if (Shell::GetElapsedTime() - invader_frame_start >= invader_move_freq)
+		if (t - invader_frame_start >= invader_move_freq)
 		{
 			MoveInvaders();		
 
-			invader_frame_start = Shell::GetElapsedTime();
+			invader_frame_start = t;
 		}
 
 		// Update all invaders
 		for (int i = 0; i < NUM_INVADERS + 1; i++)
-			invaders[i]->Update();	
+			invaders[i]->Update(t);	
 
-		defender->Update();
+		defender->Update(t);
 	}
 }
 
-void Game::Render(float dp_ratio)
+void Game::Render(double t, float dp_ratio)
 {	
 	if (defender_lives <= 0)
 		return;
 
 	// Render all available shields
 	for (int i = 0; i < NUM_SHIELDS; i++)
-	{
 		shields[i]->Render(dp_ratio);
-	}
-
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) texture);
-	glColor4ub(255, 255, 255, 255);
-	glBegin(GL_QUADS);
 
 	// Render all available invaders
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
-	{
-		invaders[i]->Render(dp_ratio);
-	}
+		invaders[i]->Render(dp_ratio, texture);
 	
-	defender->Render(dp_ratio);
-
-	glEnd();
+	defender->Render(t, dp_ratio, texture);
 }
 
 Defender* Game::GetDefender()

+ 3 - 3
Samples/luainvaders/src/Game.h

@@ -55,10 +55,10 @@ public:
 	void Initialise();
 
 	/// Update the game
-	void Update();
+	void Update(double t);
 
 	/// Render the game
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio);
 
 	/// Access the defender
 	Defender* GetDefender();
@@ -91,7 +91,7 @@ public:
 	bool IsGameOver() const;
 
 	/// Get the dimensions of the game window.
-	const Rml::Vector2f GetWindowDimensions();	
+	const Rml::Vector2f GetWindowDimensions();
 
 private:
 

+ 25 - 32
Samples/luainvaders/src/Invader.cpp

@@ -29,20 +29,19 @@
 #include "Invader.h"
 #include <RmlUi/Core/Math.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "Game.h"
 #include "GameDetails.h"
 #include "Shield.h"
 #include "Sprite.h"
 
-static const double BOMB_UPDATE_FREQ = 0.04;
-static const float BOMB_RAY_SPEED = 10;
-static const float BOMB_MISSILE_SPEED = 7;
-static const float BOMB_PROBABILITY_EASY = 0.002f;
-static const float BOMB_PROBABILITY_HARD = 0.005f;
-static const float EXPLOSION_TIME = 0.25;
-static const Rml::Colourb MOTHERSHIP_COLOUR = Rml::Colourb(255, 0, 0, 255);
+const float BOMB_UPDATE_FREQ = 0.04f;
+const float BOMB_RAY_SPEED = 10;
+const float BOMB_MISSILE_SPEED = 7;
+const float BOMB_PROBABILITY_EASY = 0.002f;
+const float BOMB_PROBABILITY_HARD = 0.005f;
+const float EXPLOSION_TIME = 0.25f;
+const Rml::Colourb MOTHERSHIP_COLOUR = Rml::Colourb(255, 0, 0, 255);
 
 Sprite invader_sprites[] =
 {
@@ -104,10 +103,10 @@ const Rml::Vector2f& Invader::GetPosition() const
 	return position;
 }
 
-void Invader::Update()
+void Invader::Update(double t)
 {
 	// Update the bombs
-	if (Shell::GetElapsedTime() - bomb_frame_start > BOMB_UPDATE_FREQ)
+	if (float(t - bomb_frame_start) > BOMB_UPDATE_FREQ)
 	{	
 
 		// Update the bomb position if its in flight, or check if we should drop one
@@ -142,13 +141,13 @@ void Invader::Update()
 			// Check if we hit the defender
 			if (bomb != NONE)
 			{
-				if (game->GetDefender()->CheckHit(bomb_position))
+				if (game->GetDefender()->CheckHit(t, bomb_position))
 					bomb = NONE;
 			}
 		}
-		else if (state == ALIVE &&
-				 Rml::Math::RandomReal(1.0f) < bomb_probability &&
-				 game->CanDropBomb(invader_index))
+		else if ( state == ALIVE
+				&& Rml::Math::RandomReal(1.0f) < bomb_probability 
+				&& game->CanDropBomb(invader_index))
 		{
 			bomb = Rml::Math::RandomInteger(2) == 0 ? RAY : MISSILE;
 			bomb_position = position;
@@ -160,10 +159,10 @@ void Invader::Update()
 				bomb_animation_frame = 4;
 		}	
 
-		bomb_frame_start = Shell::GetElapsedTime();
+		bomb_frame_start = t;
 	}
 
-	if (state == EXPLODING && Shell::GetElapsedTime() > death_time)
+	if (state == EXPLODING && t - death_time > 0.0)
 		state = DEAD;
 }
 
@@ -182,27 +181,21 @@ void Invader::UpdateAnimation()
 	}
 }
 
-void Invader::Render(float dp_ratio)
+void Invader::Render(float dp_ratio, Rml::TextureHandle texture)
 {
+	Rml::Colourb color(255);
+
 	if (type == MOTHERSHIP)
-	{
-		glColor4ubv(MOTHERSHIP_COLOUR);
-	}
+		color = MOTHERSHIP_COLOUR;
+
 	int sprite_index = GetSpriteIndex();
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 
 	if (state != DEAD)
-		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio);
+		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio, color, texture);
 	
 	if (bomb != NONE)
-	{
-		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio);
-	}
-
-	if (type == MOTHERSHIP)
-	{
-		glColor4ub(255, 255, 255, 255);
-	}
+		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio, color, texture);
 }
 
 Invader::InvaderState Invader::GetState()
@@ -210,7 +203,7 @@ Invader::InvaderState Invader::GetState()
 	return state;
 }
 
-bool Invader::CheckHit(const Rml::Vector2f& check_position)
+bool Invader::CheckHit(double t, const Rml::Vector2f& check_position)
 {
 	// Get the sprite index we're currently using for collision detection
 	int sprite_index = GetSpriteIndex();
@@ -241,7 +234,7 @@ bool Invader::CheckHit(const Rml::Vector2f& check_position)
 
 		// Set our state to exploding and start the timer to our doom
 		state = EXPLODING;
-		death_time = Shell::GetElapsedTime() + EXPLOSION_TIME;	
+		death_time = t + EXPLOSION_TIME;	
 
 		return true;
 	}
@@ -256,7 +249,7 @@ int Invader::GetSpriteIndex() const
 	switch (type)
 	{
 		RMLUI_UNUSED_SWITCH_ENUM(UNKNOWN);
-		case RANK1:                 break;      // animation_frame is the right index already
+		case RANK1: break;	// animation_frame is the right index already
 		case RANK2:	index += 2; break;
 		case RANK3:	index += 4; break;
 		case MOTHERSHIP: index = 6; break;

+ 6 - 6
Samples/luainvaders/src/Invader.h

@@ -41,13 +41,13 @@ class Game;
 
 class Invader
 {
-public:	
+public:
 	enum InvaderType { UNKNOWN, RANK1, RANK2, RANK3, MOTHERSHIP };
 	enum BombType { NONE, RAY, MISSILE };
 
 	/// Construct the invader
 	Invader(Game* game, InvaderType type, int index);
-	virtual ~Invader();	
+	virtual ~Invader();
 
 	/// Set the invaders screen position
 	/// @param position Position in screen space
@@ -57,10 +57,10 @@ public:
 	const Rml::Vector2f& GetPosition() const;
 
 	/// Update the invader
-	virtual void Update();	
+	virtual void Update(double t);
 
 	/// Render the invader
-	void Render(float dp_ratio);
+	void Render(float dp_ratio, Rml::TextureHandle texture);
 
 	/// Update the invaders animation
 	void UpdateAnimation();
@@ -75,7 +75,7 @@ public:
 	/// If a hit is detected, will explode and start the death timer
 	/// @param position Position to do the hit check at
 	/// @returns If the invader was hit
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 protected:
 	// Game this invader is in
@@ -107,7 +107,7 @@ protected:
 	float bomb_probability;
 
 	// Time when we should die - 0, until we're hit
-	double death_time;	
+	double death_time;
 
 	int GetSpriteIndex() const;
 };

+ 8 - 8
Samples/luainvaders/src/Mothership.cpp

@@ -32,11 +32,11 @@
 #include "Game.h"
 #include "Sprite.h"
 
-static const int SPRITE_WIDTH = 64;
+const int SPRITE_WIDTH = 64;
 
-static const float APPEARANCE_PROBABILITY = 0.001f;
-static const double UPDATE_FREQ = 0.025;
-static const float MOVEMENT_SPEED = 5;
+const float APPEARANCE_PROBABILITY = 0.001f;
+const double UPDATE_FREQ = 0.025;
+const float MOVEMENT_SPEED = 5;
 
 Mothership::Mothership(Game* game, int index) : Invader(game, Invader::MOTHERSHIP, index)
 {
@@ -51,12 +51,12 @@ Mothership::~Mothership()
 {
 }
 
-void Mothership::Update()
+void Mothership::Update(double t)
 {
 	// Generic Invader update
-	Invader::Update();
+	Invader::Update(t);
 
-	if (Shell::GetElapsedTime() - update_frame_start < UPDATE_FREQ)
+	if (t - update_frame_start < UPDATE_FREQ)
 		return;
 
 	// We're alive, keep moving!
@@ -68,7 +68,7 @@ void Mothership::Update()
 			|| (direction > 0.0f && position.x > game->GetWindowDimensions().x))
 			state = DEAD;
 
-		update_frame_start = Shell::GetElapsedTime();
+		update_frame_start = t;
 	}
 	// Determine if we should come out of hiding
 	else if (Rml::Math::RandomReal(1.0f) < APPEARANCE_PROBABILITY)

+ 1 - 1
Samples/luainvaders/src/Mothership.h

@@ -41,7 +41,7 @@ public:
 	~Mothership();
 
 	/// Update the mothership
-	void Update() override;
+	void Update(double t) override;
 
 private:
 	// Time of the last update

+ 5 - 10
Samples/luainvaders/src/Shield.cpp

@@ -28,7 +28,6 @@
 
 #include "Shield.h"
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
 #include "Game.h"
 #include "GameDetails.h"
 #include "Sprite.h"
@@ -126,11 +125,9 @@ void Shield::Render(float dp_ratio)
 		const Rml::Vector2f scaled_position = (dp_ratio * position).Round();
 		const int scaled_pixel = Rml::Math::RoundUpToInteger(PIXEL_SIZE * dp_ratio);
 
-		glPointSize((GLfloat)scaled_pixel);
-		glDisable(GL_TEXTURE_2D);
-		glColor4ubv(GameDetails::GetDefenderColour());
-
-		glBegin(GL_POINTS);
+		Rml::Colourb color = GameDetails::GetDefenderColour();
+		ColoredPointList points;
+		points.reserve(NUM_SHIELD_CELLS * NUM_SHIELD_CELLS);
 
 		for (int i = 0; i < NUM_SHIELD_CELLS; i++)
 		{
@@ -139,14 +136,12 @@ void Shield::Render(float dp_ratio)
 				if (shield_cells[i][j] == ON)
 				{
 					Rml::Vector2f cell_position = scaled_position + Rml::Vector2f(float(scaled_pixel * i), float(scaled_pixel * j));
-					glVertex2f(cell_position.x, cell_position.y);
+					points.push_back(ColoredPoint{color, cell_position});
 				}
 			}
 		}
 
-		glEnd();
-
-		glEnable(GL_TEXTURE_2D);
+		DrawPoints((float)scaled_pixel, points);
 	}
 }
 

+ 49 - 18
Samples/luainvaders/src/Sprite.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -27,33 +27,64 @@
  */
 
 #include "Sprite.h"
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/GeometryUtilities.h>
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
+#include <RmlUi/Core/RenderInterface.h>
 
-Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
-{
-}
+Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) :
+	dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
+{}
+
+Sprite::~Sprite() {}
 
-Sprite::~Sprite()
+void Sprite::Render(Rml::Vector2f position, const float dp_ratio, Rml::Colourb color, Rml::TextureHandle texture)
 {
+	Rml::RenderInterface* render_interface = Rml::GetRenderInterface();
+	if (!render_interface)
+		return;
+
+	position = dp_ratio * position;
+	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+
+	Rml::Vertex vertices[4];
+	int indices[6];
+	Rml::GeometryUtilities::GenerateQuad(vertices, indices, Rml::Vector2f(0.f), dimensions_px, color, top_left_texcoord, bottom_right_texcoord);
+
+	render_interface->RenderGeometry(vertices, 4, indices, 6, texture, position);
 }
 
-void Sprite::Render(Rml::Vector2f position, const float dp_ratio)
+void DrawPoints(float point_size, const ColoredPointList& points)
 {
-	position = (dp_ratio * position);
-	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+	Rml::RenderInterface* render_interface = Rml::GetRenderInterface();
+	if (!render_interface)
+		return;
 
-	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+	constexpr int num_quad_vertices = 4;
+	constexpr int num_quad_indices = 6;
+
+	const int num_points = (int)points.size();
+
+	Rml::Vector<Rml::Vertex> vertices(num_points * num_quad_vertices);
+	Rml::Vector<int> indices(num_points * num_quad_indices);
+
+	int vertex_offset = 0;
+	int index_offset = 0;
 
-	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x, position.y);
+	for (const ColoredPoint& point : points)
+	{
+		Rml::Vector2f position = point.position;
+		Rml::Vector2f size = Rml::Vector2f(point_size);
+		Rml::GeometryUtilities::GenerateQuad(vertices.data() + vertex_offset, indices.data() + index_offset, position, size, point.color,
+			vertex_offset);
 
-	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x, position.y + dimensions_px.y);
+		vertex_offset += num_quad_vertices;
+		index_offset += num_quad_indices;
+	}
 
-	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x + dimensions_px.x, position.y + dimensions_px.y);
+	RMLUI_ASSERT(vertex_offset == (int)vertices.size());
+	RMLUI_ASSERT(index_offset == (int)indices.size());
 
-	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x + dimensions_px.x, position.y);
+	render_interface->RenderGeometry(vertices.data(), vertex_offset, indices.data(), index_offset, {}, Rml::Vector2f(0.f));
 }

+ 10 - 3
Samples/luainvaders/src/Sprite.h

@@ -35,17 +35,24 @@
 	@author Peter Curry
  */
 
-class Sprite
-{
+class Sprite {
 public:
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	~Sprite();
 
-	void Render(Rml::Vector2f position, float dp_ratio);
+	void Render(Rml::Vector2f position, float dp_ratio, Rml::Colourb color, Rml::TextureHandle texture);
 
 	Rml::Vector2f dimensions;
 	Rml::Vector2f top_left_texcoord;
 	Rml::Vector2f bottom_right_texcoord;
 };
 
+struct ColoredPoint {
+	Rml::Colourb color;
+	Rml::Vector2f position;
+};
+using ColoredPointList = Rml::Vector<ColoredPoint>;
+
+void DrawPoints(float point_size, const ColoredPointList& points);
+
 #endif