cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

display.c (6646B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "config.h"
     21
     22#include "client.h"
     23#include "common/iconv.h"
     24#include "common/surface.h"
     25#include "vnc.h"
     26
     27#include <cairo/cairo.h>
     28#include <guacamole/client.h>
     29#include <guacamole/layer.h>
     30#include <guacamole/mem.h>
     31#include <guacamole/protocol.h>
     32#include <guacamole/socket.h>
     33#include <rfb/rfbclient.h>
     34#include <rfb/rfbproto.h>
     35
     36/* Define cairo_format_stride_for_width() if missing */
     37#ifndef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
     38#define cairo_format_stride_for_width(format, width) (width*4)
     39#endif
     40
     41#include <stdarg.h>
     42#include <stdio.h>
     43#include <stdint.h>
     44#include <stdlib.h>
     45#include <syslog.h>
     46
     47void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) {
     48
     49    guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
     50    guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
     51
     52    int dx, dy;
     53
     54    /* Cairo image buffer */
     55    int stride;
     56    unsigned char* buffer;
     57    unsigned char* buffer_row_current;
     58    cairo_surface_t* surface;
     59
     60    /* VNC framebuffer */
     61    unsigned int bpp;
     62    unsigned int fb_stride;
     63    unsigned char* fb_row_current;
     64
     65    /* Ignore extra update if already handled by copyrect */
     66    if (vnc_client->copy_rect_used) {
     67        vnc_client->copy_rect_used = 0;
     68        return;
     69    }
     70
     71    /* Init Cairo buffer */
     72    stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w);
     73    buffer = guac_mem_alloc(h, stride);
     74    buffer_row_current = buffer;
     75
     76    bpp = client->format.bitsPerPixel/8;
     77    fb_stride = bpp * client->width;
     78    fb_row_current = client->frameBuffer + (y * fb_stride) + (x * bpp);
     79
     80    /* Copy image data from VNC client to PNG */
     81    for (dy = y; dy<y+h; dy++) {
     82
     83        unsigned int*  buffer_current;
     84        unsigned char* fb_current;
     85        
     86        /* Get current buffer row, advance to next */
     87        buffer_current      = (unsigned int*) buffer_row_current;
     88        buffer_row_current += stride;
     89
     90        /* Get current framebuffer row, advance to next */
     91        fb_current      = fb_row_current;
     92        fb_row_current += fb_stride;
     93
     94        for (dx = x; dx<x+w; dx++) {
     95
     96            unsigned char red, green, blue;
     97            unsigned int v;
     98
     99            switch (bpp) {
    100                case 4:
    101                    v = *((uint32_t*)  fb_current);
    102                    break;
    103
    104                case 2:
    105                    v = *((uint16_t*) fb_current);
    106                    break;
    107
    108                default:
    109                    v = *((uint8_t*)  fb_current);
    110            }
    111
    112            /* Translate value to RGB */
    113            red   = (v >> client->format.redShift)   * 0x100 / (client->format.redMax  + 1);
    114            green = (v >> client->format.greenShift) * 0x100 / (client->format.greenMax+ 1);
    115            blue  = (v >> client->format.blueShift)  * 0x100 / (client->format.blueMax + 1);
    116
    117            /* Output RGB */
    118            if (vnc_client->settings->swap_red_blue)
    119                *(buffer_current++) = (blue << 16) | (green << 8) | red;
    120            else
    121                *(buffer_current++) = (red  << 16) | (green << 8) | blue;
    122
    123            fb_current += bpp;
    124
    125        }
    126    }
    127
    128    /* Create surface from decoded buffer */
    129    surface = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_RGB24,
    130            w, h, stride);
    131
    132    /* Draw directly to default layer */
    133    guac_common_surface_draw(vnc_client->display->default_surface,
    134            x, y, surface);
    135
    136    /* Free surface */
    137    cairo_surface_destroy(surface);
    138    guac_mem_free(buffer);
    139
    140}
    141
    142void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
    143
    144    guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
    145    guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
    146
    147    /* Copy specified rectangle within default layer */
    148    guac_common_surface_copy(vnc_client->display->default_surface,
    149            src_x, src_y, w, h,
    150            vnc_client->display->default_surface, dest_x, dest_y);
    151
    152    vnc_client->copy_rect_used = 1;
    153
    154}
    155
    156void guac_vnc_set_pixel_format(rfbClient* client, int color_depth) {
    157    client->format.trueColour = 1;
    158    switch(color_depth) {
    159        case 8:
    160            client->format.depth        = 8;
    161            client->format.bitsPerPixel = 8;
    162            client->format.blueShift    = 6;
    163            client->format.redShift     = 0;
    164            client->format.greenShift   = 3;
    165            client->format.blueMax      = 3;
    166            client->format.redMax       = 7;
    167            client->format.greenMax     = 7;
    168            break;
    169
    170        case 16:
    171            client->format.depth        = 16;
    172            client->format.bitsPerPixel = 16;
    173            client->format.blueShift    = 0;
    174            client->format.redShift     = 11;
    175            client->format.greenShift   = 5;
    176            client->format.blueMax      = 0x1f;
    177            client->format.redMax       = 0x1f;
    178            client->format.greenMax     = 0x3f;
    179            break;
    180
    181        case 24:
    182        case 32:
    183        default:
    184            client->format.depth        = 24;
    185            client->format.bitsPerPixel = 32;
    186            client->format.blueShift    = 0;
    187            client->format.redShift     = 16;
    188            client->format.greenShift   = 8;
    189            client->format.blueMax      = 0xff;
    190            client->format.redMax       = 0xff;
    191            client->format.greenMax     = 0xff;
    192    }
    193}
    194
    195rfbBool guac_vnc_malloc_framebuffer(rfbClient* rfb_client) {
    196
    197    guac_client* gc = rfbClientGetClientData(rfb_client, GUAC_VNC_CLIENT_KEY);
    198    guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;
    199
    200    /* Resize surface */
    201    if (vnc_client->display != NULL)
    202        guac_common_surface_resize(vnc_client->display->default_surface,
    203                rfb_client->width, rfb_client->height);
    204
    205    /* Use original, wrapped proc */
    206    return vnc_client->rfb_MallocFrameBuffer(rfb_client);
    207}
    208