Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Unified Diff: command_buffer/samples/bubble/bubble_module.cc

Issue 212018: Change command buffer client code to use structures.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/o3d/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « command_buffer/common/cross/resource.h ('k') | command_buffer/service/cross/buffer_rpc_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: command_buffer/samples/bubble/bubble_module.cc
===================================================================
--- command_buffer/samples/bubble/bubble_module.cc (revision 26638)
+++ command_buffer/samples/bubble/bubble_module.cc (working copy)
@@ -38,7 +38,7 @@
#ifdef __native_demo__
#include <sys/nacl_syscalls.h>
#else
-#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h"
+#include "native_client/src/shared/imc/nacl_imc.h"
#endif
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/common/cross/rpc_imc.h"
@@ -50,8 +50,7 @@
#include "command_buffer/samples/bubble/perlin_noise.h"
#include "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h" // NOLINT
-#include "native_client/intermodule_comm/nacl_imc.h"
-#include "native_client/tools/npapi_runtime/nacl_npapi.h"
+#include "native_client/src/shared/npruntime/nacl_npapi.h"
// Cube map data is hard-coded in cubemap.cc as a byte array.
// Format is 64x64xBRGA, D3D face ordering (+X, -X, +Y, -Y, +Z, -Z).
@@ -68,7 +67,7 @@
HELPER->Finish(); \
BufferSyncInterface::ParseError error = \
HELPER->interface()->GetParseError(); \
- if (error != BufferSyncInterface::PARSE_NO_ERROR) { \
+ if (error != BufferSyncInterface::kParseNoError) { \
printf("CMD error %d at %s:%d\n", error, __FILE__, __LINE__); \
} \
} while (false)
@@ -122,7 +121,7 @@
args[4].value_float = color.alpha;
args[5].value_float = depth;
args[6].value_uint32 = stencil;
- cmd_buffer->AddCommand(command_buffer::CLEAR, 7, args);
+ cmd_buffer->AddCommand(command_buffer::kClear, 7, args);
CHECK_ERROR(cmd_buffer);
}
@@ -145,7 +144,7 @@
args[3].value_uint32 = height;
args[4].value_float = z_near;
args[5].value_float = z_far;
- cmd_buffer->AddCommand(command_buffer::SET_VIEWPORT, 6, args);
+ cmd_buffer->AddCommand(command_buffer::kSetViewport, 6, args);
CHECK_ERROR(cmd_buffer);
}
@@ -311,9 +310,10 @@
// Gets current time in microseconds.
uint64_t GetTimeUsec() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000000ULL + tv.tv_usec;
+ return 0ULL;
+// struct timeval tv;
+// gettimeofday(&tv, NULL);
+// return tv.tv_sec * 1000000ULL + tv.tv_usec;
}
class BubbleDemo {
@@ -485,14 +485,14 @@
// AddCommand copies the args, so it is safe to re-use args across various
// calls.
- // 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices).
+ // 20 is the largest command we use (SetParamDataImmediate for matrices).
CommandBufferEntry args[20];
// Create geometry arrays and structures
args[0].value_uint32 = vertex_buffer_id_;
args[1].value_uint32 = kVertexBufferSize; // size
args[2].value_uint32 = 0; // flags
- helper_->AddCommand(CREATE_VERTEX_BUFFER, 3, args);
+ helper_->AddCommand(CreateVertexBuffer, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = vertex_buffer_id_;
@@ -500,13 +500,13 @@
args[2].value_uint32 = kVertexBufferSize; // size
args[3].value_uint32 = shm_id_; // shm
args[4].value_uint32 = allocator_->GetOffset(vertices_); // offset in shm
- helper_->AddCommand(SET_VERTEX_BUFFER_DATA, 5, args);
+ helper_->AddCommand(SetVertexBufferData, 5, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = index_buffer_id_;
args[1].value_uint32 = kIndexBufferSize; // size
args[2].value_uint32 = index_buffer::INDEX_32BIT; // flags
- helper_->AddCommand(CREATE_INDEX_BUFFER, 3, args);
+ helper_->AddCommand(CreateIndexBuffer, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = index_buffer_id_;
@@ -514,12 +514,12 @@
args[2].value_uint32 = kIndexBufferSize; // size
args[3].value_uint32 = shm_id_; // shm
args[4].value_uint32 = allocator_->GetOffset(indices_); // offset in shm
- helper_->AddCommand(SET_INDEX_BUFFER_DATA, 5, args);
+ helper_->AddCommand(SetIndexBufferData, 5, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = vertex_struct_id_;
args[1].value_uint32 = 3; // input count
- helper_->AddCommand(CREATE_VERTEX_STRUCT, 2, args);
+ helper_->AddCommand(CreateVertexStruct, 2, args);
CHECK_ERROR(helper_);
// Set POSITION input stream
@@ -532,7 +532,7 @@
set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT3) |
set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::POSITION) |
set_vertex_input_cmd::SemanticIndex::MakeValue(0);
- helper_->AddCommand(SET_VERTEX_INPUT, 5, args);
+ helper_->AddCommand(SetVertexInput, 5, args);
CHECK_ERROR(helper_);
// Set NORMAL input stream
@@ -543,7 +543,7 @@
set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT3) |
set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::NORMAL) |
set_vertex_input_cmd::SemanticIndex::MakeValue(0);
- helper_->AddCommand(SET_VERTEX_INPUT, 5, args);
+ helper_->AddCommand(SetVertexInput, 5, args);
CHECK_ERROR(helper_);
// Set TEXCOORD0 input stream
@@ -554,7 +554,7 @@
set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT2) |
set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::TEX_COORD) |
set_vertex_input_cmd::SemanticIndex::MakeValue(0);
- helper_->AddCommand(SET_VERTEX_INPUT, 5, args);
+ helper_->AddCommand(SetVertexInput, 5, args);
CHECK_ERROR(helper_);
// Create a 2D texture.
@@ -566,7 +566,7 @@
create_texture_2d_cmd::Levels::MakeValue(0) |
create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) |
create_texture_2d_cmd::Flags::MakeValue(0);
- helper_->AddCommand(CREATE_TEXTURE_2D, 3, args);
+ helper_->AddCommand(CreateTexture2d, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = noise_texture_id_;
@@ -585,16 +585,16 @@
args[7].value_uint32 = kTexSize; // size
args[8].value_uint32 = shm_id_;
args[9].value_uint32 = allocator_->GetOffset(noise_texture_);
- helper_->AddCommand(SET_TEXTURE_DATA, 10, args);
+ helper_->AddCommand(SetTextureData, 10, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = noise_sampler_id_;
- helper_->AddCommand(CREATE_SAMPLER, 1, args);
+ helper_->AddCommand(CreateSampler, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = noise_sampler_id_;
args[1].value_uint32 = noise_texture_id_;
- helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args);
+ helper_->AddCommand(SetSamplerTexture, 2, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = noise_sampler_id_;
@@ -606,7 +606,7 @@
set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) |
set_sampler_states::MipFilter::MakeValue(sampler::NONE) |
set_sampler_states::MaxAnisotropy::MakeValue(1);
- helper_->AddCommand(SET_SAMPLER_STATES, 2, args);
+ helper_->AddCommand(SetSamplerStates, 2, args);
CHECK_ERROR(helper_);
// Create a 2D texture.
@@ -618,7 +618,7 @@
create_texture_2d_cmd::Levels::MakeValue(0) |
create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) |
create_texture_2d_cmd::Flags::MakeValue(0);
- helper_->AddCommand(CREATE_TEXTURE_2D, 3, args);
+ helper_->AddCommand(CreateTexture2d, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = iridescence_texture_id_;
@@ -637,16 +637,16 @@
args[7].value_uint32 = kTexSize; // size
args[8].value_uint32 = shm_id_;
args[9].value_uint32 = allocator_->GetOffset(iridescence_texture_);
- helper_->AddCommand(SET_TEXTURE_DATA, 10, args);
+ helper_->AddCommand(SetTextureData, 10, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = iridescence_sampler_id_;
- helper_->AddCommand(CREATE_SAMPLER, 1, args);
+ helper_->AddCommand(CreateSampler, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = iridescence_sampler_id_;
args[1].value_uint32 = iridescence_texture_id_;
- helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args);
+ helper_->AddCommand(SetSamplerTexture, 2, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = iridescence_sampler_id_;
@@ -658,7 +658,7 @@
set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) |
set_sampler_states::MipFilter::MakeValue(sampler::NONE) |
set_sampler_states::MaxAnisotropy::MakeValue(1);
- helper_->AddCommand(SET_SAMPLER_STATES, 2, args);
+ helper_->AddCommand(SetSamplerStates, 2, args);
CHECK_ERROR(helper_);
// Create a Cubemap texture.
@@ -669,7 +669,7 @@
create_texture_cube_cmd::Levels::MakeValue(0) |
create_texture_cube_cmd::Format::MakeValue(texture::ARGB8) |
create_texture_cube_cmd::Flags::MakeValue(0);
- helper_->AddCommand(CREATE_TEXTURE_CUBE, 3, args);
+ helper_->AddCommand(CreateTextureCube, 3, args);
CHECK_ERROR(helper_);
for (unsigned int face = 0; face < 6; ++face) {
@@ -693,18 +693,18 @@
args[7].value_uint32 = kCubeMapFaceSize; // size
args[8].value_uint32 = shm_id_;
args[9].value_uint32 = allocator_->GetOffset(data);
- helper_->AddCommand(SET_TEXTURE_DATA, 10, args);
+ helper_->AddCommand(SetTextureData, 10, args);
CHECK_ERROR(helper_);
allocator_->FreePendingToken(data, helper_->InsertToken());
}
args[0].value_uint32 = cubemap_sampler_id_;
- helper_->AddCommand(CREATE_SAMPLER, 1, args);
+ helper_->AddCommand(CreateSampler, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = cubemap_sampler_id_;
args[1].value_uint32 = cubemap_id_;
- helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args);
+ helper_->AddCommand(SetSamplerTexture, 2, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = cubemap_sampler_id_;
@@ -716,7 +716,7 @@
set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) |
set_sampler_states::MipFilter::MakeValue(sampler::NONE) |
set_sampler_states::MaxAnisotropy::MakeValue(1);
- helper_->AddCommand(SET_SAMPLER_STATES, 2, args);
+ helper_->AddCommand(SetSamplerStates, 2, args);
CHECK_ERROR(helper_);
// Create the effect, and parameters.
@@ -726,7 +726,7 @@
args[1].value_uint32 = sizeof(effect_data); // size
args[2].value_uint32 = shm_id_; // shm
args[3].value_uint32 = allocator_->GetOffset(data); // offset in shm
- helper_->AddCommand(CREATE_EFFECT, 4, args);
+ helper_->AddCommand(CreateEffect, 4, args);
CHECK_ERROR(helper_);
allocator_->FreePendingToken(data, helper_->InsertToken());
@@ -737,7 +737,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -748,7 +748,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -759,7 +759,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -770,7 +770,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -781,7 +781,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -792,7 +792,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -803,7 +803,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -814,7 +814,7 @@
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
- helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args);
+ helper_->AddCommand(CreateParamByNameImmediate, 3 + arg_count, args);
CHECK_ERROR(helper_);
}
@@ -822,19 +822,19 @@
args[0].value_uint32 = noise_sampler_param_id_;
args[1].value_uint32 = sizeof(Uint32); // NOLINT
args[2].value_uint32 = noise_sampler_id_;
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args);
+ helper_->AddCommand(SetParamDataImmediate, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = iridescence_sampler_param_id_;
args[1].value_uint32 = sizeof(Uint32); // NOLINT
args[2].value_uint32 = iridescence_sampler_id_;
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args);
+ helper_->AddCommand(SetParamDataImmediate, 3, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = cubemap_sampler_param_id_;
args[1].value_uint32 = sizeof(Uint32); // NOLINT
args[2].value_uint32 = cubemap_sampler_id_;
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args);
+ helper_->AddCommand(SetParamDataImmediate, 3, args);
CHECK_ERROR(helper_);
// Create our random bubbles.
@@ -900,35 +900,35 @@
// AddCommand copies the args, so it is safe to re-use args across various
// calls.
- // 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices).
+ // 20 is the largest command we use (SetParamDataImmediate for matrices).
CommandBufferEntry args[20];
args[0].value_uint32 = vertex_struct_id_;
- helper_->AddCommand(SET_VERTEX_STRUCT, 1, args);
+ helper_->AddCommand(SetVertexStruct, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = mvp_param_id_;
args[1].value_uint32 = sizeof(mvp);
unsigned int arg_count = CopyToArgs(args + 2, &mvp, sizeof(mvp));
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args);
+ helper_->AddCommand(SetParamDataImmediate, 2 + arg_count, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = world_param_id_;
args[1].value_uint32 = sizeof(model);
arg_count = CopyToArgs(args + 2, &model, sizeof(model));
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args);
+ helper_->AddCommand(SetParamDataImmediate, 2 + arg_count, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = worldIT_param_id_;
args[1].value_uint32 = sizeof(modelIT);
arg_count = CopyToArgs(args + 2, &modelIT, sizeof(modelIT));
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args);
+ helper_->AddCommand(SetParamDataImmediate, 2 + arg_count, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = eye_param_id_;
args[1].value_uint32 = sizeof(eye);
arg_count = CopyToArgs(args + 2, &eye, sizeof(eye));
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args);
+ helper_->AddCommand(SetParamDataImmediate, 2 + arg_count, args);
CHECK_ERROR(helper_);
args[0].value_uint32 =
@@ -938,11 +938,11 @@
set_blending::ColorEq::MakeValue(GAPIInterface::BLEND_EQ_ADD) |
set_blending::SeparateAlpha::MakeValue(0) |
set_blending::Enable::MakeValue(1);
- helper_->AddCommand(SET_BLENDING, 1, args);
+ helper_->AddCommand(SetBlending, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = effect_id_;
- helper_->AddCommand(SET_EFFECT, 1, args);
+ helper_->AddCommand(SetEffect, 1, args);
CHECK_ERROR(helper_);
// Draw back faces first.
@@ -950,7 +950,7 @@
set_polygon_raster::FillMode::MakeValue(
GAPIInterface::POLYGON_MODE_FILL) |
set_polygon_raster::CullMode::MakeValue(GAPIInterface::CULL_CCW);
- helper_->AddCommand(SET_POLYGON_RASTER, 1, args);
+ helper_->AddCommand(SetPolygonRaster, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = thickness_param_id_;
@@ -959,7 +959,7 @@
args[3].value_float = bubble.base_thickness;
args[4].value_float = bubble.noise_ratio;
args[5].value_float = .5f; // back face attenuation
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 6, args);
+ helper_->AddCommand(SetParamDataImmediate, 6, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = GAPIInterface::TRIANGLES;
@@ -968,7 +968,7 @@
args[3].value_uint32 = kIndexCount/3; // primitive count
args[4].value_uint32 = 0; // min index
args[5].value_uint32 = kVertexCount-1; // max index
- helper_->AddCommand(DRAW_INDEXED, 6, args);
+ helper_->AddCommand(DrawIndexed, 6, args);
CHECK_ERROR(helper_);
// Then front faces.
@@ -976,7 +976,7 @@
set_polygon_raster::FillMode::MakeValue(
GAPIInterface::POLYGON_MODE_FILL) |
set_polygon_raster::CullMode::MakeValue(GAPIInterface::CULL_CW);
- helper_->AddCommand(SET_POLYGON_RASTER, 1, args);
+ helper_->AddCommand(SetPolygonRaster, 1, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = thickness_param_id_;
@@ -985,7 +985,7 @@
args[3].value_float = bubble.base_thickness;
args[4].value_float = bubble.noise_ratio;
args[5].value_float = 1.f;
- helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 6, args);
+ helper_->AddCommand(SetParamDataImmediate, 6, args);
CHECK_ERROR(helper_);
args[0].value_uint32 = GAPIInterface::TRIANGLES;
@@ -994,7 +994,7 @@
args[3].value_uint32 = kIndexCount/3; // primitive count
args[4].value_uint32 = 0; // min index
args[5].value_uint32 = kVertexCount-1; // max index
- helper_->AddCommand(DRAW_INDEXED, 6, args);
+ helper_->AddCommand(DrawIndexed, 6, args);
CHECK_ERROR(helper_);
}
@@ -1012,7 +1012,7 @@
math::CreatePerspectiveMatrix(kPi / 4.f, 1.f, .1f, 10000.f);
math::Matrix4 view = math::Matrix4::lookAt(eye, target, up);
- helper_->AddCommand(BEGIN_FRAME, 0 , NULL);
+ helper_->AddCommand(BeginFrame, 0 , NULL);
CHECK_ERROR(helper_);
RGBA color = {0.2f, 0.2f, 0.2f, 1.f};
ClearCmd(helper_.get(), GAPIInterface::COLOR | GAPIInterface::DEPTH, color,
@@ -1026,7 +1026,7 @@
DrawBubble(view, proj, bubble, time_ * 2.f * kPi * bubble.rotation_speed);
}
- helper_->AddCommand(END_FRAME, 0 , NULL);
+ helper_->AddCommand(EndFrame, 0 , NULL);
CHECK_ERROR(helper_);
helper_->Flush();
}
« no previous file with comments | « command_buffer/common/cross/resource.h ('k') | command_buffer/service/cross/buffer_rpc_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698