Browse Source

Designed a visual interface for mock-up level design tools in Sandbox.

David Piuva 5 years ago
parent
commit
7030057d08
3 changed files with 147 additions and 51 deletions
  1. 58 5
      Source/SDK/sandbox/media/interface.lof
  2. 89 40
      Source/SDK/sandbox/sandbox.cpp
  3. 0 6
      Source/SDK/sandbox/tool.cpp

+ 58 - 5
Source/SDK/sandbox/media/interface.lof

@@ -5,19 +5,72 @@ Begin : Panel
 		Name = "toolPanel"
 		Name = "toolPanel"
 		Left = +0
 		Left = +0
 		Top = +0
 		Top = +0
-		Right = +70
-		Bottom = +50
+		Right = 10%+100
+		Bottom = 100%
 		Solid = 1
 		Solid = 1
 		Color = 100,150,100
 		Color = 100,150,100
 		Begin : Button
 		Begin : Button
-			Name = "ExitButton"
-			Text = "Exit"
+			Name = "spriteButton"
+			Text = "Sprite"
 			Left = +10
 			Left = +10
 			Top = +10
 			Top = +10
-			Right = +60
+			Right = 50%-5
 			Bottom = +40
 			Bottom = +40
 			Color = 200,200,200
 			Color = 200,200,200
 		End
 		End
+		Begin : Button
+			Name = "modelButton"
+			Text = "Model"
+			Left = 50%+5
+			Top = +10
+			Right = 100%-10
+			Bottom = +40
+			Color = 200,200,200
+		End
+		Begin : Panel
+			Name = "spritePanel"
+			Solid = 0
+			Top = +40
+			Begin : Button
+				Name = "leftButton"
+				Text = "<"
+				Left = +10
+				Top = +10
+				Right = 50%-5
+				Bottom = +40
+				Color = 200,200,200
+			End
+			Begin : Button
+				Name = "rightButton"
+				Text = ">"
+				Left = 50%+5
+				Top = +10
+				Right = 100%-10
+				Bottom = +40
+				Color = 200,200,200
+			End
+			Begin : ListBox
+				Name = "spriteList"
+				Left = +10
+				Top = +50
+				Right = 100%-10
+				Bottom = 100%-10
+				Color = 50,75,50
+			End
+		End
+		Begin : Panel
+			Name = "modelPanel"
+			Solid = 0
+			Top = +40
+			Begin : ListBox
+				Name = "modelList"
+				Left = +10
+				Top = +10
+				Right = 100%-10
+				Bottom = 100%-10
+				Color = 50,75,50
+			End
+		End
 	End
 	End
 End
 End
 
 

+ 89 - 40
Source/SDK/sandbox/sandbox.cpp

@@ -30,6 +30,7 @@ BUGS:
 			An optional triangle patch can be added along the open sides. (all for planes and excluding sides for cylinders)
 			An optional triangle patch can be added along the open sides. (all for planes and excluding sides for cylinders)
 
 
 VISUALS:
 VISUALS:
+	* Implement freely rotated background models in the sprite engine.
 	* Make a directed light source that casts light and shadows from a fixed direction but can fade like a point light.
 	* Make a directed light source that casts light and shadows from a fixed direction but can fade like a point light.
 		Useful for street-lights and sky-lights that want to avoid normalizing and projecting light directions per pixel.
 		Useful for street-lights and sky-lights that want to avoid normalizing and projecting light directions per pixel.
 		Can be used both with and without casting shadows.
 		Can be used both with and without casting shadows.
@@ -71,6 +72,7 @@ VISUALS:
 		The first cubemap will be persistent and used later for dynamic light.
 		The first cubemap will be persistent and used later for dynamic light.
 		The later cubemaps will be temporary when generating the background's softer light.
 		The later cubemaps will be temporary when generating the background's softer light.
 USABILITY:
 USABILITY:
+	* Tool for placing freely rotated isometric models into the background.
 	* Tool for selecting and removing passive sprites.
 	* Tool for selecting and removing passive sprites.
 		Use both unique handles for simplicity and the raw look-up for handling multiple sprites at once:
 		Use both unique handles for simplicity and the raw look-up for handling multiple sprites at once:
 			Given an optional integer argument (defaulted to zero) to background sprite construction.
 			Given an optional integer argument (defaulted to zero) to background sprite construction.
@@ -131,13 +133,9 @@ static bool running = true;
 static IVector2D mousePos;
 static IVector2D mousePos;
 static bool panorate = false;
 static bool panorate = false;
 static bool tileAlign = false;
 static bool tileAlign = false;
-static bool showOverlays = true;
 static int debugView = 0;
 static int debugView = 0;
 static int mouseLights = 1;
 static int mouseLights = 1;
 
 
-// The window handle
-static Window window;
-
 static int random(const int minimum, const int maximum) {
 static int random(const int minimum, const int maximum) {
 	if (maximum > minimum) {
 	if (maximum > minimum) {
 		return (std::rand() % (maximum + 1 - minimum)) + minimum;
 		return (std::rand() % (maximum + 1 - minimum)) + minimum;
@@ -158,6 +156,29 @@ static SpriteWorld world;
 bool ambientLight = true;
 bool ambientLight = true;
 int testModelCount = 0;
 int testModelCount = 0;
 
 
+// GUI
+static Window window;
+Component mainPanel, spritePanel, spriteList, modelPanel, modelList;
+static int overlayMode = 2;
+	static const int OverlayMode_None = 0;
+	static const int OverlayMode_Profiling = 1;
+	static const int OverlayMode_Tools = 2;
+	static const int OverlayModeCount = 3;
+static int tool = 0;
+	static const int Tool_PlaceSprite = 0;
+	static const int Tool_PlaceModel = 1;
+	static const int ToolCount = 2;
+void updateOverlay() {
+	component_setProperty_integer(mainPanel, U"Visible", overlayMode == OverlayMode_Tools);
+		component_setProperty_integer(spritePanel, U"Visible", tool == Tool_PlaceSprite);
+		component_setProperty_integer(modelPanel, U"Visible", tool == Tool_PlaceModel);
+}
+
+void loadSprite(const ReadableString& name) {
+	sprite_loadTypeFromFile(imagePath, name);
+	component_call(spriteList, U"PushElement", name);
+}
+
 void sandbox_main() {
 void sandbox_main() {
 	// Create the world
 	// Create the world
 	world = spriteWorld_create(OrthoSystem(string_load(string_combine(mediaPath, U"Ortho.ini"))), 256);
 	world = spriteWorld_create(OrthoSystem(string_load(string_combine(mediaPath, U"Ortho.ini"))), 256);
@@ -206,17 +227,10 @@ void sandbox_main() {
 			} else if (key == DsrKey_Y) {
 			} else if (key == DsrKey_Y) {
 				testModelCount = (testModelCount + 1) % 11;
 				testModelCount = (testModelCount + 1) % 11;
 			} else if (key == DsrKey_F) {
 			} else if (key == DsrKey_F) {
-				showOverlays = !showOverlays;
+				overlayMode = (overlayMode + 1) % OverlayModeCount;
+				updateOverlay();
 			} else if (key == DsrKey_K) {
 			} else if (key == DsrKey_K) {
 				mouseLights = (mouseLights + 1) % 5;
 				mouseLights = (mouseLights + 1) % 5;
-			} else if (key == DsrKey_Q) {
-				// Previous type
-				brush.typeIndex = (brush.typeIndex + sprite_getTypeCount() - 1) % sprite_getTypeCount();
-			} else if (key == DsrKey_E) {
-				// Next type
-				brush.typeIndex = (brush.typeIndex + 1) % sprite_getTypeCount();
-			} else if (key == DsrKey_X) {
-				brush.direction = correctDirection(brush.direction + dir90);
 			} else if (key == DsrKey_C) {
 			} else if (key == DsrKey_C) {
 				// Rotate the world clockwise using four camera angles
 				// Rotate the world clockwise using four camera angles
 				spriteWorld_setCameraDirectionIndex(world, (spriteWorld_getCameraDirectionIndex(world) + 1) % 4);
 				spriteWorld_setCameraDirectionIndex(world, (spriteWorld_getCameraDirectionIndex(world) + 1) % 4);
@@ -253,11 +267,17 @@ void sandbox_main() {
 		cameraMovement.y = buttonPressed[3] - buttonPressed[2];
 		cameraMovement.y = buttonPressed[3] - buttonPressed[2];
 	});
 	});
 	// Get component handles and assign actions
 	// Get component handles and assign actions
-	Component mainPanel = window_getRoot(window);
+	mainPanel = window_getRoot(window);
 	component_setMouseDownEvent(mainPanel, [](const MouseEvent& event) {
 	component_setMouseDownEvent(mainPanel, [](const MouseEvent& event) {
 		if (event.key == MouseKeyEnum::Left) {
 		if (event.key == MouseKeyEnum::Left) {
-			// Place a new visual instance using the brush
-			spriteWorld_addBackgroundSprite(world, brush);
+			if (overlayMode == OverlayMode_Tools) {
+				if (tool == Tool_PlaceSprite) {
+					// Place a new visual instance using the brush
+					spriteWorld_addBackgroundSprite(world, brush);
+				} else if (tool == Tool_PlaceModel) {
+					// TODO: Implement a way to place a background model with 3-dimensional location, 3-axis rotation and uniform scaling
+				}
+			}
 		} else if (event.key == MouseKeyEnum::Right) {
 		} else if (event.key == MouseKeyEnum::Right) {
 			panorate = true;
 			panorate = true;
 		}
 		}
@@ -275,18 +295,46 @@ void sandbox_main() {
 		}
 		}
 	});
 	});
 
 
-	Component exitButton = window_findComponentByName(window, U"ExitButton");
-	component_setPressedEvent(exitButton, []() {
-		running = false;
+	mainPanel = window_findComponentByName(window, U"mainPanel");
+	spritePanel = window_findComponentByName(window, U"spritePanel");
+	modelPanel = window_findComponentByName(window, U"modelPanel");
+	component_setPressedEvent(window_findComponentByName(window, U"spriteButton"), []() {
+		tool = Tool_PlaceSprite;
+		updateOverlay();
+	});
+	component_setPressedEvent(window_findComponentByName(window, U"modelButton"), []() {
+		tool = Tool_PlaceModel;
+		updateOverlay();
+	});
+	spriteList = window_findComponentByName(window, U"spriteList");
+	component_setSelectEvent(spriteList, [](int64_t index) {
+		brush.typeIndex = index;
+	});
+	modelList = window_findComponentByName(window, U"modelList");
+	component_setSelectEvent(modelList, [](int64_t index) {
+		// TODO: Implement model selection from the list
+	});
+	component_setPressedEvent(window_findComponentByName(window, U"leftButton"), []() {
+		brush.direction = correctDirection(brush.direction + dir270);
+	});
+	component_setPressedEvent(window_findComponentByName(window, U"rightButton"), []() {
+		brush.direction = correctDirection(brush.direction + dir90);
 	});
 	});
+	updateOverlay();
 
 
-	// Create sprite types
-	sprite_loadTypeFromFile(imagePath, U"Floor");
-	sprite_loadTypeFromFile(imagePath, U"WoodenFloor");
-	sprite_loadTypeFromFile(imagePath, U"WoodenFence");
-	sprite_loadTypeFromFile(imagePath, U"WoodenBarrel");
-	sprite_loadTypeFromFile(imagePath, U"Pillar");
-	sprite_loadTypeFromFile(imagePath, U"Character_Mage");
+	// Create sprite types while listing their presence in the tool menu
+	loadSprite(U"Floor");
+	loadSprite(U"WoodenFloor");
+	loadSprite(U"WoodenFence");
+	loadSprite(U"WoodenBarrel");
+	loadSprite(U"Pillar");
+	loadSprite(U"Character_Mage");
+
+	// Load models
+	DenseModel barrelVisible = DenseModel_create(importer_loadModel(modelPath + U"Barrel_LowDetail.ply", true, Transform3D()));
+	Model barrelShadow = importer_loadModel(modelPath + U"Barrel_Shadow.ply", true, Transform3D());
+	//DenseModel barrelVisible = DenseModel_create(importer_loadModel(modelPath + U"Character_Mage.ply", true, Transform3D()));
+	//Model barrelShadow = importer_loadModel(modelPath + U"Character_Mage_Shadow.ply", true, Transform3D());
 
 
 	// Create passive sprites
 	// Create passive sprites
 	for (int z = -300; z < 300; z++) {
 	for (int z = -300; z < 300; z++) {
@@ -318,12 +366,6 @@ void sandbox_main() {
 	float profileFrameRate = 0.0f;
 	float profileFrameRate = 0.0f;
 	double maxFrameTime = 0.0, lastMaxFrameTime = 0.0; // Peak per second
 	double maxFrameTime = 0.0, lastMaxFrameTime = 0.0; // Peak per second
 
 
-	// Load models
-	DenseModel barrelVisible = DenseModel_create(importer_loadModel(modelPath + U"Barrel_LowDetail.ply", true, Transform3D()));
-	Model barrelShadow = importer_loadModel(modelPath + U"Barrel_Shadow.ply", true, Transform3D());
-	//DenseModel barrelVisible = DenseModel_create(importer_loadModel(modelPath + U"Character_Mage.ply", true, Transform3D()));
-	//Model barrelShadow = importer_loadModel(modelPath + U"Character_Mage_Shadow.ply", true, Transform3D());
-
 	while(running) {
 	while(running) {
 		double timer = time_getSeconds();
 		double timer = time_getSeconds();
 		double startTime;
 		double startTime;
@@ -384,7 +426,14 @@ void sandbox_main() {
 		}
 		}
 
 
 		// Show the brush
 		// Show the brush
-		spriteWorld_addTemporarySprite(world, brush);
+		if (overlayMode == OverlayMode_Tools) {
+			if (tool == Tool_PlaceSprite) {
+				spriteWorld_addTemporarySprite(world, brush);
+			} else if (tool == Tool_PlaceModel) {
+				// TODO: Implement preview of freely rotated background model brush
+				//spriteWorld_addTemporaryModel(world, ModelInstance(?, ?, ?));
+			}
+		}
 
 
 		// Test freely rotated models
 		// Test freely rotated models
 		for(int t = 0; t < testModelCount; t++) {
 		for(int t = 0; t < testModelCount; t++) {
@@ -418,13 +467,13 @@ void sandbox_main() {
 			draw_copy(colorBuffer, spriteWorld_getLightBuffer(world));
 			draw_copy(colorBuffer, spriteWorld_getLightBuffer(world));
 		}
 		}
 
 
-		// Overlays mode
-		if (showOverlays) {
-			startTime = time_getSeconds();
-				window_drawComponents(window);
-			debugText("Draw GUI: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
-
-			IVector2D writer = IVector2D(10, 55);
+		// Overlays
+		startTime = time_getSeconds();
+			window_drawComponents(window);
+		debugText("Draw GUI: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
+		// Profiling mode
+		if (overlayMode == OverlayMode_Profiling) {
+			IVector2D writer = IVector2D(10, 10);
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"FPS: ", profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"FPS: ", profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"avg ms: ", 1000.0f / profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"avg ms: ", 1000.0f / profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"max ms: ", 1000.0f * lastMaxFrameTime), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 			font_printLine(colorBuffer, font_getDefault(), string_combine(U"max ms: ", 1000.0f * lastMaxFrameTime), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;

+ 0 - 6
Source/SDK/sandbox/tool.cpp

@@ -1,10 +1,4 @@
 
 
-/*
-	TODO:
-		* Make alternative models for animated characters and damaged buildings.
-		* Make the custom rendering system able to render directly into a game with triangle culling and clipping.
-*/
-
 #include <assert.h>
 #include <assert.h>
 #include <limits>
 #include <limits>
 #include <functional>
 #include <functional>