Panda3D
 All Classes Functions Variables Enumerations
rocketRenderInterface.cxx
1 // Filename: rocketRenderInterface.cxx
2 // Created by: rdb (04Nov11)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "rocketRenderInterface.h"
16 #include "cullableObject.h"
17 #include "cullHandler.h"
18 #include "geomVertexData.h"
19 #include "geomVertexArrayData.h"
20 #include "internalName.h"
21 #include "geomVertexWriter.h"
22 #include "geomTriangles.h"
23 #include "colorAttrib.h"
24 #include "colorBlendAttrib.h"
25 #include "cullBinAttrib.h"
26 #include "depthTestAttrib.h"
27 #include "depthWriteAttrib.h"
28 #include "scissorAttrib.h"
29 #include "texture.h"
30 #include "textureAttrib.h"
31 #include "texturePool.h"
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: RocketRenderInterface::render
35 // Access: Public
36 // Description: Called by RocketNode in cull_callback. Invokes
37 // context->Render() and culls the result.
38 ////////////////////////////////////////////////////////////////////
40 render(Rocket::Core::Context* context, CullTraverser *trav) {
41  nassertv(context != NULL);
42  MutexHolder holder(_lock);
43 
44  _trav = trav;
45  _net_transform = trav->get_world_transform();
46  _net_state = RenderState::make(
47  CullBinAttrib::make("unsorted", 0),
48  DepthTestAttrib::make(RenderAttrib::M_none),
49  DepthWriteAttrib::make(DepthWriteAttrib::M_off),
50  ColorBlendAttrib::make(ColorBlendAttrib::M_add,
51  ColorBlendAttrib::O_incoming_alpha,
52  ColorBlendAttrib::O_one_minus_incoming_alpha
53  ),
54  ColorAttrib::make_vertex()
55  );
56  _dimensions = context->GetDimensions();
57 
58  context->Render();
59 
60  _trav = NULL;
61  _net_transform = NULL;
62  _net_state = NULL;
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: RocketRenderInterface::make_geom
67 // Access: Protected
68 // Description: Called internally to make a Geom from Rocket data.
69 ////////////////////////////////////////////////////////////////////
71 make_geom(Rocket::Core::Vertex* vertices,
72  int num_vertices, int* indices, int num_indices,
73  GeomEnums::UsageHint uh, const LVecBase2 &tex_scale) {
74 
75  PT(GeomVertexData) vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4t2(), uh);
76  vdata->unclean_set_num_rows(num_vertices);
77  {
78  GeomVertexWriter vwriter(vdata, InternalName::get_vertex());
79  GeomVertexWriter cwriter(vdata, InternalName::get_color());
80  GeomVertexWriter twriter(vdata, InternalName::get_texcoord());
81 
82  // Write the vertex information.
83  for (int i = 0; i < num_vertices; ++i) {
84  const Rocket::Core::Vertex &vertex = vertices[i];
85 
86  vwriter.add_data3f(LVector3f::right() * vertex.position.x + LVector3f::up() * vertex.position.y);
87  cwriter.add_data4i(vertex.colour.red, vertex.colour.green,
88  vertex.colour.blue, vertex.colour.alpha);
89  twriter.add_data2f(vertex.tex_coord.x * tex_scale[0],
90  (1.0f - vertex.tex_coord.y) * tex_scale[1]);
91  }
92  }
93 
94  // Create a primitive and write the indices.
95  PT(GeomTriangles) triangles = new GeomTriangles(uh);
96  {
97  PT(GeomVertexArrayData) idata = triangles->modify_vertices();
98  idata->unclean_set_num_rows(num_indices);
99  GeomVertexWriter iwriter(idata, 0);
100 
101  for (int i = 0; i < num_indices; ++i) {
102  iwriter.add_data1i(indices[i]);
103  }
104  }
105 
106  PT(Geom) geom = new Geom(vdata);
107  geom->add_primitive(triangles);
108  return geom;
109 }
110 
111 ////////////////////////////////////////////////////////////////////
112 // Function: RocketRenderInterface::render_geom
113 // Access: Protected
114 // Description: Only call this during render(). Culls a geom.
115 ////////////////////////////////////////////////////////////////////
117 render_geom(const Geom* geom, const RenderState* state, const Rocket::Core::Vector2f& translation) {
118  LVector3 offset = LVector3::right() * translation.x + LVector3::up() * translation.y;
119 
120  if (_enable_scissor) {
121  state = state->add_attrib(ScissorAttrib::make(_scissor));
122  rocket_cat.spam()
123  << "Rendering geom " << geom << " with state "
124  << *state << ", translation (" << offset << "), "
125  << "scissor region (" << _scissor << ")\n";
126  } else {
127  rocket_cat.spam()
128  << "Rendering geom " << geom << " with state "
129  << *state << ", translation (" << offset << ")\n";
130  }
131 
132  CPT(TransformState) internal_transform =
133  _trav->get_scene()->get_cs_world_transform()->compose(
134  _net_transform->compose(TransformState::make_pos(offset)));
135 
136  CullableObject *object =
137  new CullableObject(geom, _net_state->compose(state),
138  internal_transform);
139  _trav->get_cull_handler()->record_object(object, _trav);
140 }
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: RocketRenderInterface::RenderGeometry
144 // Access: Protected
145 // Description: Called by Rocket when it wants to render geometry
146 // that the application does not wish to optimize.
147 ////////////////////////////////////////////////////////////////////
149 RenderGeometry(Rocket::Core::Vertex* vertices,
150  int num_vertices, int* indices, int num_indices,
151  Rocket::Core::TextureHandle thandle,
152  const Rocket::Core::Vector2f& translation) {
153 
154  Texture *texture = (Texture *)thandle;
155 
156  LVecBase2 tex_scale(1, 1);
157  if (texture != (Texture *)NULL) {
158  tex_scale = texture->get_tex_scale();
159  }
160 
161  PT(Geom) geom = make_geom(vertices, num_vertices, indices, num_indices,
162  GeomEnums::UH_stream, tex_scale);
163 
164  CPT(RenderState) state;
165  if (texture != (Texture *)NULL) {
166  state = RenderState::make(TextureAttrib::make(texture));
167  } else {
168  state = RenderState::make_empty();
169  }
170 
171  render_geom(geom, state, translation);
172 }
173 
174 ////////////////////////////////////////////////////////////////////
175 // Function: RocketRenderInterface::CompileGeometry
176 // Access: Protected
177 // Description: Called by Rocket when it wants to compile geometry
178 // it believes will be static for the forseeable future.
179 ////////////////////////////////////////////////////////////////////
180 Rocket::Core::CompiledGeometryHandle RocketRenderInterface::
181 CompileGeometry(Rocket::Core::Vertex* vertices,
182  int num_vertices, int* indices, int num_indices,
183  Rocket::Core::TextureHandle thandle) {
184 
185  Texture *texture = (Texture *)thandle;
186 
187  CompiledGeometry *c = new CompiledGeometry;
188  LVecBase2 tex_scale(1, 1);
189 
190  if (texture != (Texture *)NULL) {
191  rocket_cat.debug()
192  << "Compiling geom " << c->_geom << " with texture '"
193  << texture->get_name() << "'\n";
194 
195  tex_scale = texture->get_tex_scale();
196 
197  PT(TextureStage) stage = new TextureStage("");
198  stage->set_mode(TextureStage::M_modulate);
199 
200  CPT(TextureAttrib) attr = DCAST(TextureAttrib, TextureAttrib::make());
201  attr = DCAST(TextureAttrib, attr->add_on_stage(stage, (Texture *)texture));
202 
203  c->_state = RenderState::make(attr);
204 
205  } else {
206  rocket_cat.debug()
207  << "Compiling geom " << c->_geom << " without texture\n";
208 
209  c->_state = RenderState::make_empty();
210  }
211 
212  c->_geom = make_geom(vertices, num_vertices, indices, num_indices,
213  GeomEnums::UH_static, tex_scale);
214 
215  return (Rocket::Core::CompiledGeometryHandle) c;
216 }
217 
218 ////////////////////////////////////////////////////////////////////
219 // Function: RocketRenderInterface::RenderCompiledGeometry
220 // Access: Protected
221 // Description: Called by Rocket when it wants to render
222 // application-compiled geometry.
223 ////////////////////////////////////////////////////////////////////
224 void RocketRenderInterface::
225 RenderCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry, const Rocket::Core::Vector2f& translation) {
226 
227  CompiledGeometry *c = (CompiledGeometry*) geometry;
228  render_geom(c->_geom, c->_state, translation);
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: RocketRenderInterface::ReleaseCompiledGeometry
233 // Access: Protected
234 // Description: Called by Rocket when it wants to release
235 // application-compiled geometry.
236 ////////////////////////////////////////////////////////////////////
237 void RocketRenderInterface::
238 ReleaseCompiledGeometry(Rocket::Core::CompiledGeometryHandle geometry) {
239  delete (CompiledGeometry*) geometry;
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: RocketRenderInterface::LoadTexture
244 // Access: Protected
245 // Description: Called by Rocket when a texture is required by the
246 // library.
247 ////////////////////////////////////////////////////////////////////
248 bool RocketRenderInterface::
249 LoadTexture(Rocket::Core::TextureHandle& texture_handle,
250  Rocket::Core::Vector2i& texture_dimensions,
251  const Rocket::Core::String& source) {
252 
253  // Prefer padding over scaling to avoid blurring people's pixel art.
254  LoaderOptions options;
255  if (Texture::get_textures_power_2() == ATS_none) {
256  options.set_auto_texture_scale(ATS_none);
257  } else {
258  options.set_auto_texture_scale(ATS_pad);
259  }
260 
261  Filename fn = Filename::from_os_specific(source.CString());
262  PT(Texture) tex = TexturePool::load_texture(fn, 0, false, options);
263  if (tex == NULL) {
264  texture_handle = 0;
265  texture_dimensions.x = 0;
266  texture_dimensions.y = 0;
267  return false;
268  }
269 
270  tex->set_minfilter(SamplerState::FT_nearest);
271  tex->set_magfilter(SamplerState::FT_nearest);
272 
273  // Since libRocket may make layout decisions based on the size of
274  // the image, it's important that we give it the original size of
275  // the image file in order to produce consistent results.
276  int width = tex->get_orig_file_x_size();
277  int height = tex->get_orig_file_y_size();
278  if (width == 0 && height == 0) {
279  // This shouldn't happen unless someone is playing very strange
280  // tricks with the TexturePool, but we might as well handle it.
281  width = tex->get_x_size();
282  height = tex->get_y_size();
283  }
284  texture_dimensions.x = width;
285  texture_dimensions.y = height;
286 
287  tex->ref();
288  texture_handle = (Rocket::Core::TextureHandle) tex.p();
289 
290  return true;
291 }
292 
293 ////////////////////////////////////////////////////////////////////
294 // Function: RocketRenderInterface::GenerateTexture
295 // Access: Protected
296 // Description: Called by Rocket when a texture is required to be
297 // built from an internally-generated sequence of pixels.
298 ////////////////////////////////////////////////////////////////////
299 bool RocketRenderInterface::
300 GenerateTexture(Rocket::Core::TextureHandle& texture_handle,
301  const Rocket::Core::byte* source,
302  const Rocket::Core::Vector2i& source_dimensions) {
303 
304  PT(Texture) tex = new Texture;
305  tex->setup_2d_texture(source_dimensions.x, source_dimensions.y,
306  Texture::T_unsigned_byte, Texture::F_rgba);
307 
308  // Pad to nearest power of two if necessary. It may not be necessary
309  // as libRocket seems to give power-of-two sizes already, but can't hurt.
310  tex->set_size_padded(source_dimensions.x, source_dimensions.y);
311 
312  PTA_uchar image = tex->modify_ram_image();
313 
314  // Convert RGBA to BGRA
315  size_t src_stride = source_dimensions.x * 4;
316  size_t dst_stride = tex->get_x_size() * 4;
317  const unsigned char *src_ptr = source + (src_stride * source_dimensions.y);
318  unsigned char *dst_ptr = &image[0];
319 
320  for (; src_ptr > source; dst_ptr += dst_stride) {
321  src_ptr -= src_stride;
322  for (size_t i = 0; i < src_stride; i += 4) {
323  dst_ptr[i + 0] = src_ptr[i + 2];
324  dst_ptr[i + 1] = src_ptr[i + 1];
325  dst_ptr[i + 2] = src_ptr[i];
326  dst_ptr[i + 3] = src_ptr[i + 3];
327  }
328  }
329 
330  tex->set_wrap_u(SamplerState::WM_clamp);
331  tex->set_wrap_v(SamplerState::WM_clamp);
332  tex->set_minfilter(SamplerState::FT_nearest);
333  tex->set_magfilter(SamplerState::FT_nearest);
334 
335  tex->ref();
336  texture_handle = (Rocket::Core::TextureHandle) tex.p();
337 
338  return true;
339 }
340 
341 ////////////////////////////////////////////////////////////////////
342 // Function: RocketRenderInterface::ReleaseTexture
343 // Access: Protected
344 // Description: Called by Rocket when a loaded texture is no longer
345 // required.
346 ////////////////////////////////////////////////////////////////////
347 void RocketRenderInterface::
348 ReleaseTexture(Rocket::Core::TextureHandle texture_handle) {
349  Texture *tex = (Texture *)texture_handle;
350  if (tex != (Texture *)NULL) {
351  unref_delete(tex);
352  }
353 }
354 
355 ////////////////////////////////////////////////////////////////////
356 // Function: RocketRenderInterface::EnableScissorRegion
357 // Access: Protected
358 // Description: Called by Rocket when it wants to enable or disable
359 // scissoring to clip content.
360 ////////////////////////////////////////////////////////////////////
361 void RocketRenderInterface::
362 EnableScissorRegion(bool enable) {
363  _enable_scissor = enable;
364 }
365 
366 ////////////////////////////////////////////////////////////////////
367 // Function: RocketRenderInterface::SetScissorRegion
368 // Access: Protected
369 // Description: Called by Rocket when it wants to change the
370 // scissor region.
371 ////////////////////////////////////////////////////////////////////
372 void RocketRenderInterface::
373 SetScissorRegion(int x, int y, int width, int height) {
374  _scissor[0] = x / (PN_stdfloat) _dimensions.x;
375  _scissor[1] = (x + width) / (PN_stdfloat) _dimensions.x;
376  _scissor[2] = 1.0f - ((y + height) / (PN_stdfloat) _dimensions.y);
377  _scissor[3] = 1.0f - (y / (PN_stdfloat) _dimensions.y);
378 }
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
void add_data1i(int data)
Sets the write row to a particular 1-component value, and advances the write row. ...
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:26
This class exists just to provide scoping for the various enumerated types used by Geom...
Definition: geomEnums.h:27
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
LVecBase2 get_tex_scale() const
Returns a scale pair that is suitable for applying to geometry via NodePath::set_tex_scale(), which will convert texture coordinates on the geometry from the range 0..1 into the appropriate range to render the video part of the texture.
Definition: texture.I:752
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
void render(Rocket::Core::Context *context, CullTraverser *trav)
Called by RocketNode in cull_callback.
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general...
Definition: texture.I:2232
The smallest atom of cull.
void set_auto_texture_scale(AutoTextureScale scale)
Set this flag to ATS_none, ATS_up, ATS_down, or ATS_pad to control how a texture is scaled from disk ...
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
This is the base class for all two-component vectors and points.
Definition: lvecBase2.h:105
static LVector3f right(CoordinateSystem cs=CS_default)
Returns the right vector for the given coordinate system.
Definition: lvector3.h:554
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
const TransformState * get_world_transform() const
Returns the position of the starting node relative to the camera.
Definition: cullTraverser.I:94
Defines a series of disconnected triangles.
Definition: geomTriangles.h:25
This is the preferred interface for loading textures from image files.
Definition: texturePool.h:40
Class that provides the main render interface for libRocket integration.
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
Definition: lvector3.h:527
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
This is the data for one array of a GeomVertexData structure.
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332