Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/flame_3d/example/lib/components/simple_hud.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Camera controls:
'''
FPS: $fps
Projection: ${game.camera.projection.name}
Culled: ${game.world.culled}
Draw: ${game.world.context.drawCount}

Position: ${position.x.toStringAsFixed(2)}, ${position.y.toStringAsFixed(2)}, ${position.z.toStringAsFixed(2)}
Target: ${target.x.toStringAsFixed(2)}, ${target.y.toStringAsFixed(2)}, ${target.z.toStringAsFixed(2)}
Expand Down
2 changes: 1 addition & 1 deletion packages/flame_3d/example/lib/example_game_3d.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ExampleGame3D extends FlameGame3D<World3D, ExampleCamera3D>

ExampleGame3D()
: super(
world: World3D(clearColor: const Color(0xFFFFFFFF)),
world: World3D(),
camera: ExampleCamera3D(),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@ class _ObjectGroup extends Object3D {
}) : super(children: children);

@override
void bind(GraphicsDevice device) {}
void draw(RenderContext context) {}
}
1 change: 1 addition & 0 deletions packages/flame_3d/lib/game.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export 'core.dart';
export 'src/game/flame_game_3d.dart';
export 'src/game/game_3d.dart';
export 'src/game/notifying_quaternion.dart';
export 'src/game/notifying_vector3.dart';
export 'src/game/transform_3d.dart';
2 changes: 2 additions & 0 deletions packages/flame_3d/lib/graphics.dart
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export 'src/graphics/graphics_device.dart';
export 'src/graphics/render_context.dart';
export 'src/graphics/render_context_3d.dart';
46 changes: 16 additions & 30 deletions packages/flame_3d/lib/src/camera/world_3d.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:ui';
import 'package:flame/components.dart' as flame;
import 'package:flame_3d/camera.dart';
import 'package:flame_3d/components.dart';
import 'package:flame_3d/game.dart';
import 'package:flame_3d/graphics.dart';
import 'package:flame_3d/resources.dart';
import 'package:flutter/widgets.dart' show MediaQuery;
Expand All @@ -14,20 +15,17 @@ import 'package:meta/meta.dart';
/// The primary feature of this component is that it allows [Component3D]s to
/// render directly to a [GraphicsDevice] instead of the regular rendering.
/// {@endtemplate}
class World3D extends flame.World with flame.HasGameReference {
class World3D extends flame.World with flame.HasGameReference<FlameGame3D> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make sense for it to declare T extends FlameGame3D, HasGameReference<T>, in case a user wants to extend World3D and also have a ref to their own game class?

/// {@macro world_3d}
World3D({
super.children,
super.priority,
Color clearColor = const Color(0x00000000),
}) : device = GraphicsDevice(clearValue: clearColor);

/// The graphical device attached to this world.
@internal
final GraphicsDevice device;
});

final List<Light> _lights = [];

RenderContext3D get context => game.context;

/// Register a [light] with this world.
@internal
void addLight(Light light) => _lights.add(light);
Expand All @@ -36,44 +34,32 @@ class World3D extends flame.World with flame.HasGameReference {
@internal
void removeLight(Light light) => _lights.remove(light);

final _paint = Paint();

@internal
@override
void renderFromCamera(Canvas canvas) {
final camera = CameraComponent3D.currentCamera!;
final viewport = camera.viewport;
final Viewport(virtualSize: size) = camera.viewport;

final devicePixelRatio = MediaQuery.of(game.buildContext!).devicePixelRatio;
final size = Size(
viewport.virtualSize.x * devicePixelRatio,
viewport.virtualSize.y * devicePixelRatio,
);
final pixelRatio = MediaQuery.devicePixelRatioOf(game.buildContext!);
final renderSize = Size(size.x * pixelRatio, size.y * pixelRatio);

device
context
..lights = _lights
// Set the view matrix
..view.setFrom(camera.viewMatrix)
// Set the projection matrix
..projection.setFrom(camera.projectionMatrix)
..begin(size);

culled = 0;
..setCamera(camera.viewMatrix, camera.projectionMatrix);

// ignore: invalid_use_of_internal_member
game.device.beginPass(renderSize);
super.renderFromCamera(canvas);
context.flush();

final image = device.end();
final image = game.device.endPass();
canvas.drawImageRect(
image,
Offset.zero & size,
(-viewport.virtualSize / 2).toOffset() &
Size(viewport.virtualSize.x, viewport.virtualSize.y),
Offset.zero & renderSize,
Offset(-size.x / 2, -size.y / 2) & Size(size.x, size.y),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could just be (-size / 2) & size right? (assuming size is Vector2)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but it would compute another vector so we wouldn't gain much

However we should just do a Rect.fromLTWH here honestly, that's the cheapest

_paint,
);
image.dispose();
}

// TODO(wolfenrain): this is only here for testing purposes
int culled = 0;
static final _paint = Paint();
}
10 changes: 5 additions & 5 deletions packages/flame_3d/lib/src/components/mesh_component.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flame_3d/components.dart';
import 'package:flame_3d/game.dart';
import 'package:flame_3d/graphics.dart';
import 'package:flame_3d/resources.dart';
import 'package:flame_3d/src/camera/camera_component_3d.dart';
import 'package:flame_3d/src/graphics/graphics_device.dart';

/// {@template mesh_component}
/// An [Object3D] that renders a [Mesh] at the [position] with the [rotation]
Expand All @@ -28,14 +28,14 @@ class MeshComponent extends Object3D {
Aabb3? computeLocalAabb() => mesh.aabb;

@override
void bind(GraphicsDevice device) {
device
void draw(covariant RenderContext3D context) {
context
..model.setFrom(worldTransformMatrix)
..bindMesh(mesh);
..drawMesh(mesh);
}

@override
bool shouldCull(CameraComponent3D camera) {
bool isVisible(CameraComponent3D camera) {
return camera.frustum.intersectsWithAabb3(aabb);
}
}
25 changes: 6 additions & 19 deletions packages/flame_3d/lib/src/components/object_3d.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import 'package:flame_3d/resources.dart';
/// {@template object_3d}
/// [Object3D]s are the basic building blocks for a 3D [FlameGame].
///
/// It is an object that is positioned in 3D space and can be bind to be
/// rendered by a [GraphicsDevice].
/// It is an object that is positioned in 3D space and can be drawn by a
/// [RenderContext].
///
/// However, it has no visual representation of its own (except in
/// debug mode). It is common, therefore, to derive from this class
Expand Down Expand Up @@ -48,7 +48,6 @@ abstract class Object3D extends Component3D {

// Result is fully outside, skip children and self.
if (cullResult == CullResult.outside) {
world.culled++;
return;
}

Expand All @@ -60,26 +59,14 @@ abstract class Object3D extends Component3D {
super.renderTree(canvas);
_ancestorFullyInside = wasAncestorFullyInside;

if (cullResult == CullResult.inside || shouldCull(camera!)) {
// We set the priority to the distance between the camera and the object.
// This ensures that our rendering is done in a specific order allowing
// for alpha blending.
//
// Note(wolfenrain): we should optimize this in the long run it currently
// sucks.
priority = -(CameraComponent3D.currentCamera!.position - position).length
.abs()
.toInt();

bind(world.device);
} else {
world.culled++;
if (cullResult == CullResult.inside || isVisible(camera!)) {
world.context.submitDraw(this, worldTransformMatrix);
}
}

void bind(GraphicsDevice device);
void draw(RenderContext context);

bool shouldCull(CameraComponent3D camera) {
bool isVisible(CameraComponent3D camera) {
return camera.frustum.containsVector3(position);
}
}
8 changes: 4 additions & 4 deletions packages/flame_3d/lib/src/game/flame_game_3d.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import 'dart:ui';

import 'package:flame/game.dart';
import 'package:flame_3d/camera.dart';
import 'package:flame_3d/game.dart';

class FlameGame3D<W extends World3D, C extends CameraComponent3D>
extends FlameGame<W> {
extends FlameGame<W>
with Game3D {
FlameGame3D({
super.children,
W? world,
C? camera,
}) : super(
world: world ?? World3D(clearColor: const Color(0xFFFFFFFF)) as W,
world: world ?? World3D() as W,
camera: camera ?? CameraComponent3D() as C,
);

Expand Down
20 changes: 20 additions & 0 deletions packages/flame_3d/lib/src/game/game_3d.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'dart:ui';

import 'package:flame/game.dart';
import 'package:flame_3d/graphics.dart';
import 'package:meta/meta.dart';

mixin Game3D on Game {
@internal
final GraphicsDevice device = GraphicsDevice();

@internal
late final RenderContext3D context = RenderContext3D(device);

@override
void render(Canvas canvas) {
device.begin();
super.render(canvas);
device.end();
}
}
Loading
Loading