18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <stdio.h>
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <stdlib.h>
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/c/ppb_image_data.h"
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/graphics_2d.h"
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/image_data.h"
118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/input_event.h"
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/instance.h"
138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/module.h"
148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/cpp/point.h"
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#ifdef WIN32
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#undef PostMessage
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Allow 'this' in initializer list
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#pragma warning(disable : 4355)
218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace {
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)static const int kMouseRadius = 20;
268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)uint8_t RandUint8(uint8_t min, uint8_t max) {
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint64_t r = rand();
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint8_t result = static_cast<uint8_t>(r * (max - min + 1) / RAND_MAX) + min;
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return result;
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)uint32_t MakeColor(uint8_t r, uint8_t g, uint8_t b) {
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint8_t a = 255;
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  PP_ImageDataFormat format = pp::ImageData::GetNativeImageDataFormat();
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (format == PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return (a << 24) | (r << 16) | (g << 8) | b;
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return (a << 24) | (b << 16) | (g << 8) | r;
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class Graphics2DInstance : public pp::Instance {
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public:
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  explicit Graphics2DInstance(PP_Instance instance)
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : pp::Instance(instance),
498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        callback_factory_(this),
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        mouse_down_(false),
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        buffer_(NULL) {}
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ~Graphics2DInstance() { delete[] buffer_; }
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    unsigned int seed = 1;
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    srand(seed);
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    CreatePalette();
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return true;
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual void DidChangeView(const pp::View& view) {
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    pp::Size new_size = view.GetRect().size();
668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!CreateContext(new_size))
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return;
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // When flush_context_ is null, it means there is no Flush callback in
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // flight. This may have happened if the context was not created
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // successfully, or if this is the first call to DidChangeView (when the
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // module first starts). In either case, start the main loop.
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (flush_context_.is_null())
758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      MainLoop(0);
768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual bool HandleInputEvent(const pp::InputEvent& event) {
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!buffer_)
808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return true;
818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN ||
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        event.GetType() == PP_INPUTEVENT_TYPE_MOUSEMOVE) {
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      pp::MouseInputEvent mouse_event(event);
858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_NONE)
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        return true;
888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      mouse_ = mouse_event.GetPosition();
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      mouse_down_ = true;
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP)
948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      mouse_down_ = false;
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return true;
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private:
1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void CreatePalette() {
1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (int i = 0; i < 64; ++i) {
1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // Black -> Red
1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      palette_[i] = MakeColor(i * 2, 0, 0);
1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      palette_[i + 64] = MakeColor(128 + i * 2, 0, 0);
1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // Red -> Yellow
1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      palette_[i + 128] = MakeColor(255, i * 4, 0);
1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // Yellow -> White
1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      palette_[i + 192] = MakeColor(255, 255, i * 4);
1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bool CreateContext(const pp::Size& new_size) {
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const bool kIsAlwaysOpaque = true;
1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    context_ = pp::Graphics2D(this, new_size, kIsAlwaysOpaque);
1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!BindGraphics(context_)) {
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      fprintf(stderr, "Unable to bind 2d context!\n");
1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      context_ = pp::Graphics2D();
1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return false;
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Allocate a buffer of palette entries of the same size as the new context.
1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    buffer_ = new uint8_t[new_size.width() * new_size.height()];
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    size_ = new_size;
1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return true;
1268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void Update() {
1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Old-school fire technique cribbed from
1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // http://ionicsolutions.net/2011/12/30/demo-fire-effect/
1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    UpdateCoals();
1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DrawMouse();
1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    UpdateFlames();
1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void UpdateCoals() {
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int width = size_.width();
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int height = size_.height();
1398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    size_t span = 0;
1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Draw two rows of random values at the bottom.
1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (int y = height - 2; y < height; ++y) {
1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      size_t offset = y * width;
1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      for (int x = 0; x < width; ++x) {
1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        // On a random chance, draw some longer strips of brighter colors.
1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        if (span || RandUint8(1, 4) == 1) {
1478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          if (!span)
1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            span = RandUint8(10, 20);
1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          buffer_[offset + x] = RandUint8(128, 255);
1508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          span--;
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        } else {
1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          buffer_[offset + x] = RandUint8(32, 96);
1538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        }
1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void UpdateFlames() {
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int width = size_.width();
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int height = size_.height();
1618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (int y = 1; y < height - 1; ++y) {
1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      size_t offset = y * width;
1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      for (int x = 1; x < width - 1; ++x) {
1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        int sum = 0;
1658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        sum += buffer_[offset - width + x - 1];
1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        sum += buffer_[offset - width + x + 1];
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        sum += buffer_[offset + x - 1];
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        sum += buffer_[offset + x + 1];
1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        sum += buffer_[offset + width + x - 1];
1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        sum += buffer_[offset + width + x];
1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        sum += buffer_[offset + width + x + 1];
1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        buffer_[offset - width + x] = sum / 7;
1738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
1748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
1758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void DrawMouse() {
1788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!mouse_down_)
1798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return;
1808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int width = size_.width();
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int height = size_.height();
1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Draw a circle at the mouse position.
1858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int radius = kMouseRadius;
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int cx = mouse_.x();
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int cy = mouse_.y();
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int minx = cx - radius <= 0 ? 1 : cx - radius;
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int maxx = cx + radius >= width ? width - 1 : cx + radius;
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int miny = cy - radius <= 0 ? 1 : cy - radius;
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int maxy = cy + radius >= height ? height - 1 : cy + radius;
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (int y = miny; y < maxy; ++y) {
1938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      for (int x = minx; x < maxx; ++x) {
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if ((x - cx) * (x - cx) + (y - cy) * (y - cy) < radius * radius)
1958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          buffer_[y * width + x] = RandUint8(192, 255);
1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
1988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void Paint() {
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // See the comment above the call to ReplaceContents below.
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PP_ImageDataFormat format = pp::ImageData::GetNativeImageDataFormat();
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const bool kDontInitToZero = false;
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    pp::ImageData image_data(this, format, size_, kDontInitToZero);
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    uint32_t* data = static_cast<uint32_t*>(image_data.data());
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!data)
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    uint32_t num_pixels = size_.width() * size_.height();
2118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    size_t offset = 0;
2128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (uint32_t i = 0; i < num_pixels; ++i) {
2138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      data[offset] = palette_[buffer_[offset]];
2148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      offset++;
2158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Using Graphics2D::ReplaceContents is the fastest way to update the
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // entire canvas every frame. According to the documentation:
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   Normally, calling PaintImageData() requires that the browser copy
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   the pixels out of the image and into the graphics context's backing
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   store. This function replaces the graphics context's backing store
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   with the given image, avoiding the copy.
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   In the case of an animation, you will want to allocate a new image for
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   the next frame. It is best if you wait until the flush callback has
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   executed before allocating this bitmap. This gives the browser the
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   option of caching the previous backing store and handing it back to
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   you (assuming the sizes match). In the optimal case, this means no
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   bitmaps are allocated during the animation, and the backing store and
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   "front buffer" (which the module is painting into) are just being
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   swapped back and forth.
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //
234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    context_.ReplaceContents(&image_data);
2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void MainLoop(int32_t) {
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (context_.is_null()) {
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // The current Graphics2D context is null, so updating and rendering is
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // pointless. Set flush_context_ to null as well, so if we get another
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // DidChangeView call, the main loop is started again.
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      flush_context_ = context_;
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Update();
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Paint();
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Store a reference to the context that is being flushed; this ensures
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the callback is called, even if context_ changes before the flush
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // completes.
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    flush_context_ = context_;
2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    context_.Flush(
2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        callback_factory_.NewCallback(&Graphics2DInstance::MainLoop));
2548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  pp::CompletionCallbackFactory<Graphics2DInstance> callback_factory_;
2578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  pp::Graphics2D context_;
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  pp::Graphics2D flush_context_;
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  pp::Size size_;
2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  pp::Point mouse_;
2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bool mouse_down_;
2628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint8_t* buffer_;
2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint32_t palette_[256];
2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)};
2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class Graphics2DModule : public pp::Module {
2678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public:
2688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  Graphics2DModule() : pp::Module() {}
2698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual ~Graphics2DModule() {}
2708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance) {
2728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return new Graphics2DInstance(instance);
2738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)};
2758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace pp {
2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)Module* CreateModule() { return new Graphics2DModule(); }
2788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace pp
279