panda3d/panda/src/rocket/rocketRenderInterface.cxx

318 lines
12 KiB
C++

// Filename: rocketRenderInterface.cxx
// Created by: rdb (04Nov11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "rocketRenderInterface.h"
#include "cullableObject.h"
#include "cullHandler.h"
#include "geomVertexData.h"
#include "geomVertexArrayData.h"
#include "internalName.h"
#include "geomVertexWriter.h"
#include "geomTriangles.h"
#include "colorBlendAttrib.h"
#include "cullBinAttrib.h"
#include "depthTestAttrib.h"
#include "depthWriteAttrib.h"
#include "scissorAttrib.h"
#include "texture.h"
#include "textureAttrib.h"
#include "texturePool.h"
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::render
// Access: Public
// Description: Called by RocketNode in cull_callback. Invokes
// context->Render() and culls the result.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
render(Rocket::Core::Context* context, CullTraverser *trav) {
nassertv(context != NULL);
MutexHolder holder(_lock);
_trav = trav;
_net_transform = trav->get_world_transform();
_net_state = RenderState::make(
CullBinAttrib::make("unsorted", 0),
DepthTestAttrib::make(RenderAttrib::M_none),
DepthWriteAttrib::make(DepthWriteAttrib::M_off),
ColorBlendAttrib::make(ColorBlendAttrib::M_add,
ColorBlendAttrib::O_incoming_alpha,
ColorBlendAttrib::O_one_minus_incoming_alpha
)
);
_dimensions = context->GetDimensions();
context->Render();
_trav = NULL;
_net_transform = NULL;
_net_state = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::make_geom
// Access: Protected
// Description: Called internally to make a Geom from Rocket data.
////////////////////////////////////////////////////////////////////
PT(Geom) RocketRenderInterface::
make_geom(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, GeomEnums::UsageHint uh) {
PT(GeomVertexData) vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4t2(), uh);
vdata->unclean_set_num_rows(num_vertices);
{
GeomVertexWriter vwriter(vdata, InternalName::get_vertex());
GeomVertexWriter cwriter(vdata, InternalName::get_color());
GeomVertexWriter twriter(vdata, InternalName::get_texcoord());
// Write the vertex information.
for (int i = 0; i < num_vertices; ++i) {
const Rocket::Core::Vertex &vertex = vertices[i];
vwriter.add_data3f(LVector3f::right() * vertex.position.x + LVector3f::up() * vertex.position.y);
cwriter.add_data4i(vertex.colour.red, vertex.colour.green,
vertex.colour.blue, vertex.colour.alpha);
twriter.add_data2f(vertex.tex_coord.x, 1.0f - vertex.tex_coord.y);
}
}
// Create a primitive and write the indices.
PT(GeomTriangles) triangles = new GeomTriangles(uh);
{
PT(GeomVertexArrayData) idata = triangles->modify_vertices();
idata->unclean_set_num_rows(num_indices);
GeomVertexWriter iwriter(idata, 0);
for (int i = 0; i < num_indices; ++i) {
iwriter.add_data1i(indices[i]);
}
}
PT(Geom) geom = new Geom(vdata);
geom->add_primitive(triangles);
return geom;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::render_geom
// Access: Protected
// Description: Only call this during render(). Culls a geom.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
render_geom(const Geom* geom, const RenderState* state, const Rocket::Core::Vector2f& translation) {
LVector3 offset = LVector3::right() * translation.x + LVector3::up() * translation.y;
if (_enable_scissor) {
state = state->add_attrib(ScissorAttrib::make(_scissor));
rocket_cat.spam()
<< "Rendering geom " << geom << " with state "
<< *state << ", translation (" << offset << "), "
<< "scissor region (" << _scissor << ")\n";
} else {
rocket_cat.spam()
<< "Rendering geom " << geom << " with state "
<< *state << ", translation (" << offset << ")\n";
}
CPT(TransformState) net_transform, modelview_transform;
net_transform = _net_transform->compose(TransformState::make_pos(offset));
modelview_transform = _trav->get_world_transform()->compose(net_transform);
CullableObject *object =
new CullableObject(geom, _net_state->compose(state),
net_transform, modelview_transform,
_trav->get_gsg());
_trav->get_cull_handler()->record_object(object, _trav);
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::RenderGeometry
// Access: Protected
// Description: Called by Rocket when it wants to render geometry
// that the application does not wish to optimize.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation) {
PT(Geom) geom = make_geom(vertices, num_vertices, indices, num_indices, GeomEnums::UH_stream);
CPT(RenderState) state;
if ((Texture*) texture != (Texture*) NULL) {
state = RenderState::make(TextureAttrib::make((Texture*) texture));
} else {
state = RenderState::make_empty();
}
render_geom(geom, state, translation);
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::CompileGeometry
// Access: Protected
// Description: Called by Rocket when it wants to compile geometry
// it believes will be static for the forseeable future.
////////////////////////////////////////////////////////////////////
Rocket::Core::CompiledGeometryHandle RocketRenderInterface::
CompileGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rocket::Core::TextureHandle texture) {
CompiledGeometry *c = new CompiledGeometry;
c->_geom = make_geom(vertices, num_vertices, indices, num_indices, GeomEnums::UH_static);
if ((Texture*) texture != (Texture*) NULL) {
PT(TextureStage) stage = new TextureStage("");
stage->set_mode(TextureStage::M_replace);
CPT(TextureAttrib) attr = DCAST(TextureAttrib, TextureAttrib::make());
attr = DCAST(TextureAttrib, attr->add_on_stage(stage, (Texture*) texture));
c->_state = RenderState::make(attr);
rocket_cat.debug()
<< "Compiled geom " << c->_geom << " with texture '"
<< ((Texture*) texture)->get_name() << "'\n";
} else {
c->_state = RenderState::make_empty();
rocket_cat.debug()
<< "Compiled geom " << c->_geom << " without texture\n";
}
return (Rocket::Core::CompiledGeometryHandle) c;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::RenderCompiledGeometry
// Access: Protected
// Description: Called by Rocket when it wants to render
// application-compiled geometry.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
RenderCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry, const Rocket::Core::Vector2f& translation) {
CompiledGeometry *c = (CompiledGeometry*) geometry;
render_geom(c->_geom, c->_state, translation);
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::ReleaseCompiledGeometry
// Access: Protected
// Description: Called by Rocket when it wants to release
// application-compiled geometry.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
ReleaseCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry) {
delete (CompiledGeometry*) geometry;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::LoadTexture
// Access: Protected
// Description: Called by Rocket when a texture is required by the
// library.
////////////////////////////////////////////////////////////////////
bool RocketRenderInterface::
LoadTexture(Rocket::Core::TextureHandle& texture_handle,
Rocket::Core::Vector2i& texture_dimensions,
const Rocket::Core::String& source) {
PT(Texture) tex = TexturePool::load_texture(Filename::from_os_specific(source.CString()));
if (tex == NULL) {
texture_handle = 0;
texture_dimensions.x = 0;
texture_dimensions.y = 0;
return false;
}
texture_dimensions.x = tex->get_x_size();
texture_dimensions.y = tex->get_y_size();
tex->ref();
texture_handle = (Rocket::Core::TextureHandle) tex.p();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::GenerateTexture
// Access: Protected
// Description: Called by Rocket when a texture is required to be
// built from an internally-generated sequence of pixels.
////////////////////////////////////////////////////////////////////
bool RocketRenderInterface::
GenerateTexture(Rocket::Core::TextureHandle& texture_handle,
const Rocket::Core::byte* source,
const Rocket::Core::Vector2i& source_dimensions) {
PT(Texture) tex = new Texture;
tex->setup_2d_texture(source_dimensions.x, source_dimensions.y,
Texture::T_unsigned_byte, Texture::F_rgba);
PTA_uchar image = tex->modify_ram_image();
// Convert RGBA to BGRA
size_t row_size = source_dimensions.x * 4;
size_t y2 = image.size();
for (size_t y = 0; y < image.size(); y += row_size) {
y2 -= row_size;
for (size_t i = 0; i < row_size; i += 4) {
image[y2 + i + 0] = source[y + i + 2];
image[y2 + i + 1] = source[y + i + 1];
image[y2 + i + 2] = source[y + i];
image[y2 + i + 3] = source[y + i + 3];
}
}
tex->set_wrap_u(Texture::WM_clamp);
tex->set_wrap_v(Texture::WM_clamp);
tex->ref();
texture_handle = (Rocket::Core::TextureHandle) tex.p();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::ReleaseTexture
// Access: Protected
// Description: Called by Rocket when a loaded texture is no longer
// required.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
ReleaseTexture(Rocket::Core::TextureHandle texture_handle) {
Texture* tex = (Texture*) texture_handle;
if (tex != (Texture*) NULL) {
tex->unref();
}
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::EnableScissorRegion
// Access: Protected
// Description: Called by Rocket when it wants to enable or disable
// scissoring to clip content.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
EnableScissorRegion(bool enable) {
_enable_scissor = enable;
}
////////////////////////////////////////////////////////////////////
// Function: RocketRenderInterface::SetScissorRegion
// Access: Protected
// Description: Called by Rocket when it wants to change the
// scissor region.
////////////////////////////////////////////////////////////////////
void RocketRenderInterface::
SetScissorRegion(int x, int y, int width, int height) {
_scissor[0] = x / (PN_stdfloat) _dimensions.x;
_scissor[1] = (x + width) / (PN_stdfloat) _dimensions.x;
_scissor[2] = 1.0f - ((y + height) / (PN_stdfloat) _dimensions.y);
_scissor[3] = 1.0f - (y / (PN_stdfloat) _dimensions.y);
}