Jelajahi Sumber

Added simple 2D functionality.

Tankernn 8 tahun lalu
induk
melakukan
cd4b7b17df

+ 4 - 4
src/main/java/eu/tankernn/gameEngine/Chunk.java

@@ -2,15 +2,15 @@ package eu.tankernn.gameEngine;
 
 import java.util.List;
 
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 
 public class Chunk {
 	private final int seed;
 	private List<Light> lights;
-	private List<Entity> entities;
+	private List<Entity3D> entities;
 	
-	public Chunk(int seed, List<Light> lights, List<Entity> entities) {
+	public Chunk(int seed, List<Light> lights, List<Entity3D> entities) {
 		this.seed = seed;
 		this.lights = lights;
 		this.entities = entities;
@@ -24,7 +24,7 @@ public class Chunk {
 		return lights;
 	}
 
-	public List<Entity> getEntities() {
+	public List<Entity3D> getEntities() {
 		return entities;
 	}
 }

+ 7 - 2
src/main/java/eu/tankernn/gameEngine/GameLauncher.java

@@ -20,8 +20,13 @@ public class GameLauncher {
 		DisplayManager.closeDisplay();
 	}
 
-	public static void init(String name) {
+	public static void init(String name, int width, int height) {
 		NativesExporter.exportNatives();
-		DisplayManager.createDisplay(name);
+		DisplayManager.createDisplay(name, width, height);
+	}
+	
+	public static void init(String name) {
+		init(name, 800, 600);
 	}
+	
 }

+ 6 - 6
src/main/java/eu/tankernn/gameEngine/MainLoop.java

@@ -13,7 +13,7 @@ import org.lwjgl.util.vector.Vector3f;
 import org.lwjgl.util.vector.Vector4f;
 
 import eu.tankernn.gameEngine.entities.Camera;
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 import eu.tankernn.gameEngine.entities.Player;
 import eu.tankernn.gameEngine.entities.PlayerCamera;
@@ -60,7 +60,7 @@ public class MainLoop {
 
 	public static final boolean DEBUG = true;
 
-	static List<Entity> entities = new ArrayList<Entity>();
+	static List<Entity3D> entities = new ArrayList<Entity3D>();
 	static List<Light> lights = new ArrayList<Light>();
 
 	public static void main(String[] args) throws IOException {
@@ -82,7 +82,7 @@ public class MainLoop {
 		TerrainPack terrainPack = new TerrainPack(loader, texturePack, blendMap, SEED);
 
 		// Player
-		Entity entity = new Entity(0, new Vector3f(0, 0, 20), new Vector3f(0, 0, 0), 1, loader.getBoundingBox(0));
+		Entity3D entity = new Entity3D(0, new Vector3f(0, 0, 20), new Vector3f(0, 0, 0), 1, loader.getBoundingBox(0));
 		entities.add(entity);
 		Player player = new Player(0, new Vector3f(10, 0, 50), new Vector3f(0, 0, 0), 1, loader.getBoundingBox(0),
 				terrainPack);
@@ -105,7 +105,7 @@ public class MainLoop {
 		textMaster.loadText(text);
 
 		// Barrel
-		Entity barrel = new Entity(1, new Vector3f(75, 10, 75), new Vector3f(0, 0, 0), 1f, loader.getBoundingBox(1));
+		Entity3D barrel = new Entity3D(1, new Vector3f(75, 10, 75), new Vector3f(0, 0, 0), 1f, loader.getBoundingBox(1));
 		entities.add(barrel);
 
 		Light sun = new Light(new Vector3f(100000, 150000, -70000), new Vector3f(1f, 1f, 1f));
@@ -122,11 +122,11 @@ public class MainLoop {
 			float x = rand.nextFloat() * 1000;
 			float z = rand.nextFloat() * 1000;
 
-			entities.add(new Entity(2, new Vector3f(x, terrainPack.getTerrainHeightByWorldPos(x, z), z), new Vector3f(),
+			entities.add(new Entity3D(2, new Vector3f(x, terrainPack.getTerrainHeightByWorldPos(x, z), z), new Vector3f(),
 					1, loader.getBoundingBox(2)));
 		}
 
-		terrainPack.addWaitingForTerrainHeight(entities.toArray(new Entity[entities.size()]));
+		terrainPack.addWaitingForTerrainHeight(entities.toArray(new Entity3D[entities.size()]));
 
 		// #### Water rendering ####
 		WaterMaster waterMaster = new WaterMaster(loader, loader.loadTexture(DUDV_MAP), loader.loadTexture(NORMAL_MAP),

+ 3 - 31
src/main/java/eu/tankernn/gameEngine/TankernnGame.java

@@ -1,44 +1,18 @@
 package eu.tankernn.gameEngine;
 
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import eu.tankernn.gameEngine.entities.Camera;
 import eu.tankernn.gameEngine.loader.Loader;
 import eu.tankernn.gameEngine.renderEngine.DisplayManager;
-import eu.tankernn.gameEngine.renderEngine.MasterRenderer;
-import eu.tankernn.gameEngine.renderEngine.skybox.Skybox;
-import eu.tankernn.gameEngine.renderEngine.water.WaterMaster;
-import eu.tankernn.gameEngine.util.InternalFile;
 
 public class TankernnGame {
-	private final String name;
+	protected final String name;
 	protected Loader loader;
-	protected MasterRenderer renderer;
-	protected WaterMaster waterMaster;
-	protected Camera camera;
-	protected Skybox sky;
 	
-	public TankernnGame(String name, Skybox skybox, String dudvMap, String normalMap) {
+	public TankernnGame(String name) {
 		this.name = name;
-		this.sky = skybox;
-		try {
-			loader = new Loader();
-			loader.readModelSpecification(new InternalFile("models.json"));
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		camera = new Camera();
-		renderer = new MasterRenderer(loader, camera, skybox);
-		try {
-			waterMaster = new WaterMaster(loader, loader.loadTexture(dudvMap), loader.loadTexture(normalMap), camera);
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		}
+		this.loader = new Loader();
 	}
 	
 	public void update() {
-		camera.update();
 	}
 	
 	public void render() {
@@ -46,9 +20,7 @@ public class TankernnGame {
 	}
 	
 	public void cleanUp() {
-		waterMaster.cleanUp();
 		loader.cleanUp();
-		renderer.cleanUp();
 	}
 	
 	public String getName() {

+ 46 - 0
src/main/java/eu/tankernn/gameEngine/TankernnGame3D.java

@@ -0,0 +1,46 @@
+package eu.tankernn.gameEngine;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import eu.tankernn.gameEngine.entities.Camera;
+import eu.tankernn.gameEngine.loader.Loader;
+import eu.tankernn.gameEngine.renderEngine.MasterRenderer;
+import eu.tankernn.gameEngine.renderEngine.skybox.Skybox;
+import eu.tankernn.gameEngine.renderEngine.water.WaterMaster;
+import eu.tankernn.gameEngine.util.InternalFile;
+
+public class TankernnGame3D extends TankernnGame {
+	protected MasterRenderer renderer;
+	protected WaterMaster waterMaster;
+	protected Camera camera;
+	protected Skybox sky;
+	
+	public TankernnGame3D(String name, Skybox skybox, String dudvMap, String normalMap) {
+		super(name);
+		this.sky = skybox;
+		try {
+			loader = new Loader();
+			loader.readModelSpecification(new InternalFile("models.json"));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		camera = new Camera();
+		renderer = new MasterRenderer(loader, camera, skybox);
+		try {
+			waterMaster = new WaterMaster(loader, loader.loadTexture(dudvMap), loader.loadTexture(normalMap), camera);
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	public void update() {
+		camera.update();
+	}
+	
+	public void cleanUp() {
+		super.cleanUp();
+		waterMaster.cleanUp();
+		renderer.cleanUp();
+	}
+}

+ 39 - 0
src/main/java/eu/tankernn/gameEngine/entities/Entity2D.java

@@ -0,0 +1,39 @@
+package eu.tankernn.gameEngine.entities;
+
+import org.lwjgl.util.vector.Vector2f;
+
+import eu.tankernn.gameEngine.loader.textures.Texture;
+import eu.tankernn.gameEngine.renderEngine.gui.GuiTexture;
+
+public class Entity2D extends GuiTexture {
+	protected Vector2f velocity = new Vector2f(0, 0);
+	
+	public Entity2D(Texture texture, Vector2f position, Vector2f scale) {
+		super(texture, position, scale);
+	}
+	
+	public void update() {
+		this.position = Vector2f.add(position, velocity, null);
+	}
+
+	public void setVelocity(Vector2f velocity) {
+		this.velocity = velocity;
+	}
+
+	public boolean collides(Entity2D b) {
+		if (Math.abs(position.x - b.getPosition().x) < scale.x + b.getSize().x) {
+			if (Math.abs(position.y - b.getPosition().y) < scale.y + b.getSize().y) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public Vector2f getPosition() {
+		return position;
+	}
+	
+	public Vector2f getSize() {
+		return super.getScale();
+	}
+}

+ 2 - 2
src/main/java/eu/tankernn/gameEngine/entities/Entity.java → src/main/java/eu/tankernn/gameEngine/entities/Entity3D.java

@@ -5,14 +5,14 @@ import org.lwjgl.util.vector.Vector3f;
 import eu.tankernn.gameEngine.loader.models.AABB;
 import eu.tankernn.gameEngine.util.IPositionable;
 
-public class Entity implements IPositionable {
+public class Entity3D implements IPositionable {
 	private int model;
 	private Vector3f position;
 	private Vector3f rotation;
 	private float scale;
 	private AABB boundingBox;
 	
-	public Entity(int model, Vector3f position, Vector3f rotation, float scale, AABB boundingBox) {
+	public Entity3D(int model, Vector3f position, Vector3f rotation, float scale, AABB boundingBox) {
 		this.model = model;
 		this.position = position;
 		this.rotation = rotation;

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/entities/Player.java

@@ -10,7 +10,7 @@ import eu.tankernn.gameEngine.settings.Physics;
 import eu.tankernn.gameEngine.terrains.Terrain;
 import eu.tankernn.gameEngine.terrains.TerrainPack;
 
-public class Player extends Entity {
+public class Player extends Entity3D {
 	
 	private static final float RUN_SPEED = 20;
 	protected static final float TURN_MAX = 160;

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/loader/font/FontType.java

@@ -37,7 +37,7 @@ public class FontType {
 	}
 
 	/**
-	 * Takes in an unloaded text and calculate all of the vertices for the quads
+	 * Takes in an unloaded text and calculates all of the vertices for the quads
 	 * on which this text will be rendered. The vertex positions and texture
 	 * coords and calculated based on the information from the font file.
 	 * 

+ 8 - 8
src/main/java/eu/tankernn/gameEngine/renderEngine/MasterRenderer.java

@@ -15,7 +15,7 @@ import org.lwjgl.opengl.GL11;
 import org.lwjgl.util.vector.Vector4f;
 
 import eu.tankernn.gameEngine.entities.Camera;
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 import eu.tankernn.gameEngine.loader.Loader;
 import eu.tankernn.gameEngine.loader.models.TexturedModel;
@@ -44,7 +44,7 @@ public class MasterRenderer {
 	private SkyboxRenderer skyboxRenderer;
 	private ShadowMapMasterRenderer shadowMapRenderer;
 	
-	private Map<TexturedModel, List<Entity>> entities = new HashMap<TexturedModel, List<Entity>>();
+	private Map<TexturedModel, List<Entity3D>> entities = new HashMap<TexturedModel, List<Entity3D>>();
 	private List<Terrain> terrains = new ArrayList<Terrain>();
 
 	/**
@@ -123,7 +123,7 @@ public class MasterRenderer {
 		for (Terrain t : scene.getTerrainPack().getTerrains()) {
 			processTerrain(t);
 		}
-		for (Entity e : scene.getEntities()) {
+		for (Entity3D e : scene.getEntities()) {
 			processEntity(e);
 		}
 	}
@@ -134,13 +134,13 @@ public class MasterRenderer {
 	 * @param entity
 	 *            Entity to add to the list
 	 */
-	public void processEntity(Entity entity) {
+	public void processEntity(Entity3D entity) {
 		TexturedModel entityModel = loader.getModel(entity.getModel());
-		List<Entity> batch = entities.get(entityModel);
+		List<Entity3D> batch = entities.get(entityModel);
 		if (batch != null) {
 			batch.add(entity);
 		} else {
-			List<Entity> newBatch = new ArrayList<Entity>();
+			List<Entity3D> newBatch = new ArrayList<Entity3D>();
 			newBatch.add(entity);
 			entities.put(entityModel, newBatch);
 		}
@@ -156,8 +156,8 @@ public class MasterRenderer {
 		terrains.add(terrain);
 	}
 
-	public void renderShadowMap(List<Entity> entityList, Light sun) {
-		for (Entity e : entityList) {
+	public void renderShadowMap(List<Entity3D> entityList, Light sun) {
+		for (Entity3D e : entityList) {
 			processEntity(e);
 		}
 		shadowMapRenderer.render(entities, sun);

+ 4 - 4
src/main/java/eu/tankernn/gameEngine/renderEngine/Scene.java

@@ -3,14 +3,14 @@ package eu.tankernn.gameEngine.renderEngine;
 import java.util.List;
 
 import eu.tankernn.gameEngine.entities.Camera;
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 import eu.tankernn.gameEngine.loader.textures.Texture;
 import eu.tankernn.gameEngine.renderEngine.skybox.Skybox;
 import eu.tankernn.gameEngine.terrains.TerrainPack;
 
 public class Scene {
-	private List<Entity> entities;
+	private List<Entity3D> entities;
 	private TerrainPack terrainPack;
 	private List<Light> lights;
 	private Camera camera;
@@ -18,7 +18,7 @@ public class Scene {
 	
 	private Texture environmentMap;
 	
-	public Scene(List<Entity> entities, TerrainPack terrainPack, List<Light> lights, Camera camera, Skybox sky) {
+	public Scene(List<Entity3D> entities, TerrainPack terrainPack, List<Light> lights, Camera camera, Skybox sky) {
 		this.entities = entities;
 		this.terrainPack = terrainPack;
 		this.lights = lights;
@@ -27,7 +27,7 @@ public class Scene {
 		this.environmentMap = Texture.newEmptyCubeMap(128);
 	}
 
-	public List<Entity> getEntities() {
+	public List<Entity3D> getEntities() {
 		return entities;
 	}
 

+ 5 - 5
src/main/java/eu/tankernn/gameEngine/renderEngine/entities/EntityRenderer.java

@@ -12,7 +12,7 @@ import org.lwjgl.util.vector.Matrix4f;
 import org.lwjgl.util.vector.Vector3f;
 import org.lwjgl.util.vector.Vector4f;
 
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 import eu.tankernn.gameEngine.loader.models.TexturedModel;
 import eu.tankernn.gameEngine.loader.textures.ModelTexture;
@@ -60,7 +60,7 @@ public class EntityRenderer<S extends EntityShader> {
 	 *            Transformation matrix to shadow space. Used for applying
 	 *            shadows.
 	 */
-	public void render(Map<TexturedModel, List<Entity>> entities, Matrix4f toShadowSpace, ICamera cam,
+	public void render(Map<TexturedModel, List<Entity3D>> entities, Matrix4f toShadowSpace, ICamera cam,
 			Vector4f clipPlane, List<Light> lights, Texture environmentMap) {
 		shader.start();
 		shader.plane.loadVec4(clipPlane);
@@ -72,8 +72,8 @@ public class EntityRenderer<S extends EntityShader> {
 		shader.cameraPosition.loadVec3(cam.getPosition());
 		for (TexturedModel model : entities.keySet()) {
 			prepareTexturedModel(model, environmentMap);
-			List<Entity> batch = entities.get(model);
-			for (Entity entity : batch) {
+			List<Entity3D> batch = entities.get(model);
+			for (Entity3D entity : batch) {
 				prepareInstance(entity, model);
 				GL11.glDrawElements(GL11.GL_TRIANGLES, model.getRawModel().getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
 			}
@@ -116,7 +116,7 @@ public class EntityRenderer<S extends EntityShader> {
 		model.getRawModel().unbind(0, 1, 2, 3);
 	}
 
-	protected void prepareInstance(Entity entity, TexturedModel model) {
+	protected void prepareInstance(Entity3D entity, TexturedModel model) {
 		Vector3f rot = entity.getRotation();
 		Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), rot.x, rot.y, rot.z,
 				entity.getScale());

+ 31 - 0
src/main/java/eu/tankernn/gameEngine/renderEngine/gui/GuiMaster.java

@@ -0,0 +1,31 @@
+package eu.tankernn.gameEngine.renderEngine.gui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.tankernn.gameEngine.loader.Loader;
+
+public class GuiMaster {
+	private GuiRenderer renderer;
+	private List<GuiTexture> guis = new ArrayList<GuiTexture>();
+	
+	public GuiMaster(Loader loader) {
+		renderer = new GuiRenderer(loader);
+	}
+	
+	public void render() {
+		renderer.render(guis);
+	}
+	
+	public void loadGui(GuiTexture gui) {
+		guis.add(gui);
+	}
+	
+	public void removeGui(GuiTexture gui) {
+		guis.remove(gui);
+	}
+
+	public void cleanUp() {
+		renderer.cleanUp();
+	}
+}

+ 2 - 2
src/main/java/eu/tankernn/gameEngine/renderEngine/gui/GuiTexture.java

@@ -7,8 +7,8 @@ import eu.tankernn.gameEngine.loader.textures.Texture;
 public class GuiTexture {
 	
 	private Texture texture;
-	private Vector2f position;
-	private Vector2f scale;
+	protected Vector2f position;
+	protected Vector2f scale;
 	
 	public GuiTexture(Texture texture, Vector2f position, Vector2f scale) {
 		this.texture = texture;

+ 4 - 4
src/main/java/eu/tankernn/gameEngine/renderEngine/shadows/ShadowMapEntityRenderer.java

@@ -9,7 +9,7 @@ import org.lwjgl.opengl.GL30;
 import org.lwjgl.util.vector.Matrix4f;
 import org.lwjgl.util.vector.Vector3f;
 
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.loader.models.TexturedModel;
 import eu.tankernn.gameEngine.renderEngine.MasterRenderer;
 import eu.tankernn.gameEngine.renderEngine.RawModel;
@@ -40,7 +40,7 @@ public class ShadowMapEntityRenderer {
 	 * @param entities
 	 *            - the entities to be rendered to the shadow map.
 	 */
-	protected void render(Map<TexturedModel, List<Entity>> entities) {
+	protected void render(Map<TexturedModel, List<Entity3D>> entities) {
 		for (TexturedModel model : entities.keySet()) {
 			RawModel rawModel = model.getRawModel();
 			bindModel(rawModel);
@@ -48,7 +48,7 @@ public class ShadowMapEntityRenderer {
 			if (model.getModelTexture().hasTransparency()) {
 				MasterRenderer.disableCulling();
 			}
-			for (Entity entity : entities.get(model)) {
+			for (Entity3D entity : entities.get(model)) {
 				prepareInstance(entity);
 				GL11.glDrawElements(GL11.GL_TRIANGLES, rawModel.getIndexCount(), GL11.GL_UNSIGNED_INT, 0);
 			}
@@ -82,7 +82,7 @@ public class ShadowMapEntityRenderer {
 	 * @param entity
 	 *            - the entity to be prepared for rendering.
 	 */
-	private void prepareInstance(Entity entity) {
+	private void prepareInstance(Entity3D entity) {
 		Vector3f rot = entity.getRotation();
 		Matrix4f modelMatrix = Maths.createTransformationMatrix(entity.getPosition(), rot.x, rot.y, rot.z,
 				entity.getScale());

+ 2 - 2
src/main/java/eu/tankernn/gameEngine/renderEngine/shadows/ShadowMapMasterRenderer.java

@@ -9,7 +9,7 @@ import org.lwjgl.util.vector.Vector2f;
 import org.lwjgl.util.vector.Vector3f;
 
 import eu.tankernn.gameEngine.entities.Camera;
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.entities.Light;
 import eu.tankernn.gameEngine.loader.models.TexturedModel;
 import eu.tankernn.gameEngine.loader.textures.Texture;
@@ -70,7 +70,7 @@ public class ShadowMapMasterRenderer {
 	 * @param sun
 	 *            - the light acting as the sun in the scene.
 	 */
-	public void render(Map<TexturedModel, List<Entity>> entities, Light sun) {
+	public void render(Map<TexturedModel, List<Entity3D>> entities, Light sun) {
 		shadowBox.update();
 		Vector3f sunPosition = sun.getPosition();
 		Vector3f lightDirection = new Vector3f(-sunPosition.x, -sunPosition.y, -sunPosition.z);

+ 7 - 7
src/main/java/eu/tankernn/gameEngine/util/MousePicker.java

@@ -10,7 +10,7 @@ import org.lwjgl.util.vector.Vector3f;
 import org.lwjgl.util.vector.Vector4f;
 
 import eu.tankernn.gameEngine.entities.Camera;
-import eu.tankernn.gameEngine.entities.Entity;
+import eu.tankernn.gameEngine.entities.Entity3D;
 import eu.tankernn.gameEngine.loader.models.AABB;
 import eu.tankernn.gameEngine.renderEngine.gui.GuiTexture;
 import eu.tankernn.gameEngine.terrains.Terrain;
@@ -28,13 +28,13 @@ public class MousePicker {
 	
 	private TerrainPack terrains;
 	private Vector3f currentTerrainPoint;
-	private List<Entity> entities;
-	private Entity currentEntity;
+	private List<Entity3D> entities;
+	private Entity3D currentEntity;
 	
 	private List<GuiTexture> guis;
 	private GuiTexture currentGui;
 	
-	public MousePicker(Camera cam, Matrix4f projection, TerrainPack terrains, List<Entity> entities, List<GuiTexture> guis) {
+	public MousePicker(Camera cam, Matrix4f projection, TerrainPack terrains, List<Entity3D> entities, List<GuiTexture> guis) {
 		camera = cam;
 		projectionMatrix = projection;
 		viewMatrix = camera.getViewMatrix();
@@ -43,7 +43,7 @@ public class MousePicker {
 		this.guis = guis;
 	}
 	
-	public Entity getCurrentEntity() {
+	public Entity3D getCurrentEntity() {
 		return currentEntity;
 	}
 	
@@ -70,7 +70,7 @@ public class MousePicker {
 		}
 		
 		boolean foundTarget = false;
-		for (Entity e: entities) {
+		for (Entity3D e: entities) {
 			if (entityInstersect(e) && !foundTarget) {
 				e.setScale(2);
 				foundTarget = true;
@@ -132,7 +132,7 @@ public class MousePicker {
 	
 	// #### Entity intersect ####
 	
-	public boolean entityInstersect(Entity entity) {
+	public boolean entityInstersect(Entity3D entity) {
 		AABB box = entity.getBoundingBox();
 		Vector3f dirfrac = new Vector3f();