Procházet zdrojové kódy

Use transient buffer for rendering sprites

Daniele Bartolini před 9 roky
rodič
revize
2e67daf3d7

+ 6 - 1
samples/core/editors/level_editor/level_editor.lua

@@ -312,9 +312,14 @@ function UnitBox:raycast(pos, dir)
 	local rw = LevelEditor._rw
 	local mesh_component = RenderWorld.mesh_instances(rw, self._unit_id)
 	if mesh_component then
-		local tm, hext = RenderWorld.mesh_obb(rw, mesh_component)
 		return RenderWorld.mesh_raycast(rw, mesh_component, pos, dir)
 	end
+
+	local sprite_component = RenderWorld.sprite_instances(rw, self._unit_id)
+	if sprite_component then
+		return RenderWorld.sprite_raycast(rw, sprite_component, pos, dir)
+	end
+
 	return -1.0
 end
 

+ 1 - 1
src/device/device.cpp

@@ -386,7 +386,7 @@ void Device::run()
 		_resource_manager->register_type(RESOURCE_TYPE_MESH,             mhr::load, mhr::unload, mhr::online, mhr::offline);
 		_resource_manager->register_type(RESOURCE_TYPE_SOUND,            sdr::load, sdr::unload, NULL,        NULL        );
 		_resource_manager->register_type(RESOURCE_TYPE_UNIT,             utr::load, utr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_SPRITE,           spr::load, spr::unload, spr::online, spr::offline);
+		_resource_manager->register_type(RESOURCE_TYPE_SPRITE,           spr::load, spr::unload, NULL,        NULL        );
 		_resource_manager->register_type(RESOURCE_TYPE_PACKAGE,          pkr::load, pkr::unload, NULL,        NULL        );
 		_resource_manager->register_type(RESOURCE_TYPE_PHYSICS,          phr::load, phr::unload, NULL,        NULL        );
 		_resource_manager->register_type(RESOURCE_TYPE_MATERIAL,         mtr::load, mtr::unload, mtr::online, mtr::offline);

+ 13 - 0
src/lua/lua_api.cpp

@@ -1923,6 +1923,18 @@ static int render_world_sprite_set_frame(lua_State* L)
 	return 0;
 }
 
+static int render_world_sprite_raycast(lua_State* L)
+{
+	LuaStack stack(L);
+	RenderWorld* rw = stack.get_render_world(1);
+	float t = rw->sprite_raycast(stack.get_sprite_instance(2)
+		, stack.get_vector3(3)
+		, stack.get_vector3(4)
+		);
+	stack.push_float(t);
+	return 1;
+}
+
 static int render_world_light_create(lua_State* L)
 {
 	LuaStack stack(L);
@@ -3362,6 +3374,7 @@ void load_api(LuaEnvironment& env)
 	env.add_module_function("RenderWorld", "sprite_instances",     render_world_sprite_instances);
 	env.add_module_function("RenderWorld", "sprite_set_frame",     render_world_sprite_set_frame);
 	env.add_module_function("RenderWorld", "sprite_set_visible",   render_world_sprite_set_visible);
+	env.add_module_function("RenderWorld", "sprite_raycast",       render_world_sprite_raycast);
 	env.add_module_function("RenderWorld", "light_create",         render_world_light_create);
 	env.add_module_function("RenderWorld", "light_destroy",        render_world_light_destroy);
 	env.add_module_function("RenderWorld", "light_instances",      render_world_light_instances);

+ 14 - 54
src/resource/sprite_resource.cpp

@@ -55,8 +55,6 @@ namespace sprite_resource_internal
 		const u32 num_frames = array::size(frames);
 
 		Array<f32> vertices(default_allocator());
-		Array<u16> indices(default_allocator());
-		u32 num_idx = 0;
 		for (u32 i = 0; i < num_frames; ++i)
 		{
 			SpriteFrame frame;
@@ -91,14 +89,9 @@ namespace sprite_resource_internal
 
 			array::push_back(vertices, x0); array::push_back(vertices, y1); // position
 			array::push_back(vertices, u0); array::push_back(vertices, v1); // uv
-
-			array::push_back(indices, u16(num_idx)); array::push_back(indices, u16(num_idx + 1)); array::push_back(indices, u16(num_idx + 2));
-			array::push_back(indices, u16(num_idx)); array::push_back(indices, u16(num_idx + 2)); array::push_back(indices, u16(num_idx + 3));
-			num_idx += 4;
 		}
 
 		const u32 num_vertices = array::size(vertices) / 4; // 4 components per vertex
-		const u32 num_indices = array::size(indices);
 
 		// Write
 		opts.write(RESOURCE_VERSION_SPRITE);
@@ -106,56 +99,15 @@ namespace sprite_resource_internal
 		opts.write(num_vertices);
 		for (u32 i = 0; i < array::size(vertices); i++)
 			opts.write(vertices[i]);
-
-		opts.write(num_indices);
-		for (u32 i = 0; i < array::size(indices); i++)
-			opts.write(indices[i]);
 	}
 
 	void* load(File& file, Allocator& a)
 	{
-		BinaryReader br(file);
-
-		u32 version;
-		br.read(version);
-
-		u32 num_verts;
-		br.read(num_verts);
-		const bgfx::Memory* vbmem = bgfx::alloc(num_verts * sizeof(f32) * 4);
-		br.read(vbmem->data, num_verts * sizeof(f32) * 4);
-
-		u32 num_inds;
-		br.read(num_inds);
-		const bgfx::Memory* ibmem = bgfx::alloc(num_inds * sizeof(u16));
-		br.read(ibmem->data, num_inds * sizeof(u16));
-
-		SpriteResource* so = (SpriteResource*) a.allocate(sizeof(SpriteResource));
-		so->vbmem = vbmem;
-		so->ibmem = ibmem;
-
-		return so;
-	}
-
-	void online(StringId64 id, ResourceManager& rm)
-	{
-		SpriteResource* so = (SpriteResource*) rm.get(RESOURCE_TYPE_SPRITE, id);
-
-		bgfx::VertexDecl decl;
-		decl.begin()
-			.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
-			.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false)
-			.end();
-
-		so->vb = bgfx::createVertexBuffer(so->vbmem, decl);
-		so->ib = bgfx::createIndexBuffer(so->ibmem);
-	}
-
-	void offline(StringId64 id, ResourceManager& rm)
-	{
-		SpriteResource* so = (SpriteResource*) rm.get(RESOURCE_TYPE_SPRITE, id);
-
-		bgfx::destroyVertexBuffer(so->vb);
-		bgfx::destroyIndexBuffer(so->ib);
+		const u32 file_size = file.size();
+		void* res = a.allocate(file_size);
+		file.read(res, file_size);
+		CE_ASSERT(*(u32*)res == RESOURCE_VERSION_SPRITE, "Wrong version");
+		return res;
 	}
 
 	void unload(Allocator& a, void* resource)
@@ -164,6 +116,14 @@ namespace sprite_resource_internal
 	}
 } // namespace sprite_resource_internal
 
+namespace sprite_resource
+{
+	const f32* frame_data(const SpriteResource* sr, u32 i)
+	{
+		return ((f32*)&sr[1]) + 16*i;
+	}
+}
+
 namespace sprite_animation_resource_internal
 {
 	void compile(const char* path, CompileOptions& opts)
@@ -205,7 +165,7 @@ namespace sprite_animation_resource_internal
 		const u32 file_size = file.size();
 		void* res = a.allocate(file_size);
 		file.read(res, file_size);
-		CE_ASSERT(*(u32*)res == RESOURCE_VERSION_SPRITE, "Wrong version");
+		CE_ASSERT(*(u32*)res == RESOURCE_VERSION_SPRITE_ANIMATION, "Wrong version");
 		return res;
 	}
 

+ 8 - 12
src/resource/sprite_resource.h

@@ -15,30 +15,26 @@
 
 namespace crown
 {
-// header
-// num_verts
-// verts[num_verts]
-// num_inds
-// inds[num_inds]
-
 struct SpriteResource
 {
 	u32 version;
-	const bgfx::Memory* vbmem;
-	const bgfx::Memory* ibmem;
-	bgfx::VertexBufferHandle vb;
-	bgfx::IndexBufferHandle ib;
+	u32 num_verts;
+	// verts[num_verts]
 };
 
 namespace sprite_resource_internal
 {
 	void compile(const char* path, CompileOptions& opts);
 	void* load(File& file, Allocator& a);
-	void online(StringId64 id, ResourceManager& rm);
-	void offline(StringId64 id, ResourceManager& rm);
 	void unload(Allocator& a, void* resource);
 } // namespace sprite_resource_internal
 
+namespace sprite_resource
+{
+	/// Returns the frame data for the frame @a i.
+	const f32* frame_data(const SpriteResource* sr, u32 i);
+} // namespace sprite_resource
+
 struct SpriteAnimationResource
 {
 	u32 version;

+ 66 - 13
src/world/render_world.cpp

@@ -163,6 +163,37 @@ void RenderWorld::sprite_set_frame(SpriteInstance i, u32 index)
 	_sprite_manager._data.frame[i.i] = index;
 }
 
+f32 RenderWorld::sprite_raycast(SpriteInstance i, const Vector3& from, const Vector3& dir)
+{
+	CE_ASSERT(i.i < _sprite_manager._data.size, "Index out of bounds");
+
+	const SpriteManager::SpriteInstanceData& sid = _sprite_manager._data;
+	const f32* frame = sprite_resource::frame_data(sid.resource[i.i], sid.frame[i.i]);
+
+	const f32 vertices[] =
+	{
+		frame[ 0], frame[ 1], 0.0f,
+		frame[ 4], frame[ 5], 0.0f,
+		frame[ 8], frame[ 9], 0.0f,
+		frame[12], frame[13], 0.0f
+	};
+
+	const u16 indices[] =
+	{
+		0, 1, 2,
+		0, 2, 3
+	};
+
+	return ray_mesh_intersection(from
+		, dir
+		, _sprite_manager._data.world[i.i]
+		, vertices
+		, sizeof(Vector3)
+		, indices
+		, 6
+		);
+}
+
 LightInstance RenderWorld::light_create(UnitId id, const LightDesc& ld, const Matrix4x4& tr)
 {
 	return _light_manager.create(id, ld, tr);
@@ -296,13 +327,42 @@ void RenderWorld::render(const Matrix4x4& view, const Matrix4x4& projection)
 	}
 
 	// Render sprites
-	for (u32 i = 0; i < sid.first_hidden; ++i)
 	{
-		bgfx::setTransform(to_float_ptr(sid.world[i]));
-		bgfx::setVertexBuffer(sid.sprite[i].vbh);
-		bgfx::setIndexBuffer(sid.sprite[i].ibh, sid.frame[i] * 6, 6);
+		bgfx::VertexDecl decl;
+		decl.begin()
+			.add(bgfx::Attrib::Position,  2, bgfx::AttribType::Float)
+			.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false)
+			.end()
+			;
+		bgfx::TransientVertexBuffer tvb;
+		bgfx::allocTransientVertexBuffer(&tvb, 4*sid.first_hidden, decl);
+		bgfx::TransientIndexBuffer tib;
+		bgfx::allocTransientIndexBuffer(&tib, 6*sid.first_hidden);
+
+		f32* vdata = (f32*)tvb.data;
+		u16* idata = (u16*)tib.data;
+
+		// Render sprites
+		for (u32 i = 0; i < sid.first_hidden; ++i)
+		{
+			const f32* frame = sprite_resource::frame_data(sid.resource[i], sid.frame[i]);
 
-		_material_manager->get(sid.material[i])->bind(*_resource_manager, *_shader_manager);
+			for (u32 i = 0; i < 16; ++i)
+				*vdata++ = *frame++;
+
+			*idata++ = i*4+0;
+			*idata++ = i*4+1;
+			*idata++ = i*4+2;
+			*idata++ = i*4+0;
+			*idata++ = i*4+2;
+			*idata++ = i*4+3;
+
+			bgfx::setTransform(to_float_ptr(sid.world[i]));
+			bgfx::setVertexBuffer(&tvb);
+			bgfx::setIndexBuffer(&tib, i*6, 6);
+
+			_material_manager->get(sid.material[i])->bind(*_resource_manager, *_shader_manager);
+		}
 	}
 }
 
@@ -602,7 +662,6 @@ void RenderWorld::SpriteManager::allocate(u32 num)
 	const u32 bytes = 0
 		+ num*sizeof(UnitId) + alignof(UnitId)
 		+ num*sizeof(SpriteResource**) + alignof(SpriteResource*)
-		+ num*sizeof(SpriteData) + alignof(SpriteData)
 		+ num*sizeof(StringId64) + alignof(StringId64)
 		+ num*sizeof(u32) + alignof(u32)
 		+ num*sizeof(Matrix4x4) + alignof(Matrix4x4)
@@ -618,8 +677,7 @@ void RenderWorld::SpriteManager::allocate(u32 num)
 
 	new_data.unit          = (UnitId*               )new_data.buffer;
 	new_data.resource      = (const SpriteResource**)memory::align_top(new_data.unit + num,     alignof(const SpriteResource*));
-	new_data.sprite        = (SpriteData*           )memory::align_top(new_data.resource + num, alignof(SpriteData           ));
-	new_data.material      = (StringId64*           )memory::align_top(new_data.sprite + num,   alignof(StringId64           ));
+	new_data.material      = (StringId64*           )memory::align_top(new_data.resource + num, alignof(StringId64           ));
 	new_data.frame         = (u32*                  )memory::align_top(new_data.material + num, alignof(u32                  ));
 	new_data.world         = (Matrix4x4*            )memory::align_top(new_data.frame + num,    alignof(Matrix4x4            ));
 	new_data.aabb          = (AABB*                 )memory::align_top(new_data.world + num,    alignof(AABB                 ));
@@ -627,7 +685,6 @@ void RenderWorld::SpriteManager::allocate(u32 num)
 
 	memcpy(new_data.unit, _data.unit, _data.size * sizeof(UnitId));
 	memcpy(new_data.resource, _data.resource, _data.size * sizeof(SpriteResource**));
-	memcpy(new_data.sprite, _data.sprite, _data.size * sizeof(SpriteData));
 	memcpy(new_data.material, _data.material, _data.size * sizeof(StringId64));
 	memcpy(new_data.frame, _data.frame, _data.size * sizeof(u32));
 	memcpy(new_data.world, _data.world, _data.size * sizeof(Matrix4x4));
@@ -652,8 +709,6 @@ SpriteInstance RenderWorld::SpriteManager::create(UnitId id, const SpriteResourc
 
 	_data.unit[last]          = id;
 	_data.resource[last]      = sr;
-	_data.sprite[last].vbh    = sr->vb;
-	_data.sprite[last].ibh    = sr->ib;
 	_data.material[last]      = mat;
 	_data.frame[last]         = 0;
 	_data.world[last]         = tr;
@@ -677,8 +732,6 @@ void RenderWorld::SpriteManager::destroy(SpriteInstance i)
 
 	_data.unit[i.i]          = _data.unit[last];
 	_data.resource[i.i]      = _data.resource[last];
-	_data.sprite[i.i].vbh    = _data.sprite[last].vbh;
-	_data.sprite[i.i].ibh    = _data.sprite[last].ibh;
 	_data.material[i.i]      = _data.material[last];
 	_data.frame[i.i]         = _data.frame[last];
 	_data.world[i.i]         = _data.world[last];

+ 4 - 7
src/world/render_world.h

@@ -65,6 +65,10 @@ public:
 	/// Sets whether the sprite @a i is @a visible.
 	void sprite_set_visible(SpriteInstance i, bool visible);
 
+	/// Returns the distance along ray (from, dir) to intersection point with sprite @a i
+	/// or -1.0 if no intersection.
+	f32 sprite_raycast(SpriteInstance i, const Vector3& from, const Vector3& dir);
+
 	/// Creates a new light instance.
 	LightInstance light_create(UnitId id, const LightDesc& ld, const Matrix4x4& tr);
 
@@ -175,12 +179,6 @@ public:
 
 	struct SpriteManager
 	{
-		struct SpriteData
-		{
-			bgfx::VertexBufferHandle vbh;
-			bgfx::IndexBufferHandle ibh;
-		};
-
 		struct SpriteInstanceData
 		{
 			u32 size;
@@ -191,7 +189,6 @@ public:
 
 			UnitId* unit;
 			const SpriteResource** resource;
-			SpriteData* sprite;
 			StringId64* material;
 			u32* frame;
 			Matrix4x4* world;