// // // Undefine stupid windows API defines that get included by the prefix headers #ifdef GetNextSibling #undef GetNextSibling #endif #ifdef GetFirstChild #undef GetFirstChild #endif // Our Assert conflicts with the definitions inside libRocket #pragma push_macro("Assert") #undef Assert #include "RocketRenderingInterface.h" #include "RocketFileInterface.h" #pragma pop_macro("Assert") #include "graphics/2d.h" #include "graphics/material.h" using namespace Rocket::Core; namespace scpui { RocketRenderingInterface::RocketRenderingInterface() { renderOffset.x = 0.0f; renderOffset.y = 0.0f; vertex_stream_buffer = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Streaming); index_stream_buffer = gr_create_buffer(BufferType::Index, BufferUsageHint::Streaming); layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(Vertex), offsetof(Vertex, position)); layout.add_vertex_component(vertex_format_data::COLOR4, sizeof(Vertex), offsetof(Vertex, colour)); layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(Vertex), offsetof(Vertex, tex_coord)); } RocketRenderingInterface::~RocketRenderingInterface() { if (vertex_stream_buffer >= 0) { gr_delete_buffer(vertex_stream_buffer); } if (index_stream_buffer >= 0) { gr_delete_buffer(index_stream_buffer); } } RocketRenderingInterface::Texture* RocketRenderingInterface::get_texture(Rocket::Core::TextureHandle handle) { return reinterpret_cast(handle); } Rocket::Core::TextureHandle RocketRenderingInterface::get_texture_handle(RocketRenderingInterface::Texture* bitmap) { return reinterpret_cast(bitmap); } CompiledGeometryHandle RocketRenderingInterface::CompileGeometry(Vertex* vertices, int num_vertices, int* indices, int num_indices, TextureHandle texture) { GR_DEBUG_SCOPE("libRocket::CompileGeometry"); auto* geom = new CompiledGeometry(); geom->vertex_buffer = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Static); gr_update_buffer_data(geom->vertex_buffer, num_vertices * sizeof(Vertex), reinterpret_cast(vertices)); geom->index_buffer = gr_create_buffer(BufferType::Index, BufferUsageHint::Static); gr_update_buffer_data(geom->index_buffer, num_indices * sizeof(int), reinterpret_cast(indices)); geom->num_elements = num_indices; geom->texture = get_texture(texture); return reinterpret_cast(geom); } void RocketRenderingInterface::RenderCompiledGeometry(CompiledGeometryHandle geometry, const Vector2f& translation) { GR_DEBUG_SCOPE("libRocket::RenderCompiledGeometry"); auto geom = reinterpret_cast(geometry); auto bitmap = -1; if (geom->texture != nullptr) { bitmap = geom->texture->handle + geom->texture->frame_num; } renderGeometry(geom->vertex_buffer, geom->index_buffer, geom->num_elements, bitmap, translation); } void RocketRenderingInterface::ReleaseCompiledGeometry(CompiledGeometryHandle geometry) { GR_DEBUG_SCOPE("libRocket::ReleaseCompiledGeometry"); auto geom = reinterpret_cast(geometry); gr_delete_buffer(geom->vertex_buffer); gr_delete_buffer(geom->index_buffer); delete geom; } void RocketRenderingInterface::EnableScissorRegion(bool enable) { GR_DEBUG_SCOPE("libRocket::EnableScissorRegion"); if (!enable) { // Disable clipping if requested gr_reset_clip(); } // If clipping is active then SetScissorRegion will be called next clipping_active = enable; } void RocketRenderingInterface::SetScissorRegion(int x, int y, int width, int height) { GR_DEBUG_SCOPE("libRocket::SetScissorRegion"); if (clipping_active) { gr_set_clip((int)(x + renderOffset.x), (int)(y + renderOffset.y), width, height, GR_RESIZE_NONE); } } bool RocketRenderingInterface::LoadTexture(TextureHandle& texture_handle, Vector2i& texture_dimensions, const String& source) { GR_DEBUG_SCOPE("libRocket::LoadTexture"); SCP_string filename; int dir_type; if (!RocketFileInterface::getCFilePath(source, filename, dir_type)) { return false; } auto period_pos = filename.rfind('.'); if (period_pos != SCP_string::npos) { filename = filename.substr(0, period_pos); } auto id = bm_load_either(filename.c_str(), nullptr, nullptr, nullptr, false, dir_type); if (id < 0) { return false; } int w, h; bm_get_info(id, &w, &h); texture_dimensions.x = w; texture_dimensions.y = h; auto* tex = new Texture(); tex->handle = id; texture_handle = get_texture_handle(tex); return true; } bool RocketRenderingInterface::GenerateTexture(TextureHandle& texture_handle, const Rocket::Core::byte* source, const Vector2i& source_dimensions) { GR_DEBUG_SCOPE("libRocket::GenerateTexture"); auto size = (size_t)(source_dimensions.x * source_dimensions.y * 4); // RGBA format std::unique_ptr buffer(new uint8_t[size]); memcpy(buffer.get(), source, size); auto id = bm_create(32, source_dimensions.x, source_dimensions.y, buffer.get()); if (id < 0) { return false; } auto* tex = new Texture(); tex->handle = id; tex->data = std::move(buffer); texture_handle = get_texture_handle(tex); return true; } void RocketRenderingInterface::ReleaseTexture(TextureHandle texture) { GR_DEBUG_SCOPE("libRocket::ReleaseTexture"); Assertion(texture, "Invalid texture handle!"); auto tex = get_texture(texture); bm_release(tex->handle); delete tex; } void RocketRenderingInterface::RenderGeometry(Vertex* vertices, int num_vertices, int* indices, int num_indices, TextureHandle texture, const Vector2f& translation) { gr_update_buffer_data(vertex_stream_buffer, sizeof(*vertices) * num_vertices, vertices); gr_update_buffer_data(index_stream_buffer, sizeof(*indices) * num_indices, indices); int bitmap; if (texture == 0) { bitmap = -1; } else { bitmap = get_texture(texture)->handle + get_texture(texture)->frame_num; } renderGeometry(vertex_stream_buffer, index_stream_buffer, num_indices, bitmap, translation); } void RocketRenderingInterface::setRenderOffset(const vec2d& render_offset) { renderOffset = render_offset; } float RocketRenderingInterface::GetPixelsPerInch() { #if SDL_VERSION_ATLEAST(2, 0, 4) auto display = os_config_read_uint("Video", "Display", 0); float ddpi; if (SDL_GetDisplayDPI(display, &ddpi, nullptr, nullptr) != 0) { mprintf(("Failed to determine display DPI: %s\n", SDL_GetError())); return 96.f; } // Diagonal DPI should be accurate enough return ddpi; #else // return a default value return 96.f; #endif } void RocketRenderingInterface::renderGeometry(int vertex_buffer, int index_buffer, int num_elements, int bitmap, const Rocket::Core::Vector2f& translation) { interface_material material; vec2d transl; transl.x = translation.x + renderOffset.x; transl.y = translation.y + renderOffset.y; material_set_rocket_interface(&material, bitmap, transl); gr_render_rocket_primitives(&material, PRIM_TYPE_TRIS, &layout, num_elements, vertex_buffer, index_buffer); } int RocketRenderingInterface::getBitmapNum(Rocket::Core::TextureHandle handle) { int bitmap; if (handle == 0) { bitmap = -1; } else { bitmap = get_texture(handle)->handle; } return bitmap; } void RocketRenderingInterface::setAnimationFrame(Rocket::Core::TextureHandle handle, int frame) { Assertion(handle != 0, "Invalid handle for setAnimationFrame"); get_texture(handle)->frame_num = frame; } } // namespace scpui