1/*
2 * Copyright (C) 2010 David McPaul
3 *
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7// This class merges buffers together
8// Merge is called everytime a primary buffer needs to be passed downstream
9// This should allow different framerates to be handled by buffering slower
10// buffer producers and discarding buffers from faster producers
11// TODO ColorConversion
12
13#include "BufferMixer.h"
14
15BufferMixer::BufferMixer() {
16}
17
18BufferMixer::~BufferMixer() {
19}
20
21bool
22BufferMixer::isBufferAvailable() {
23	return groupedBuffers[0] != NULL;
24}
25
26// Should only be called after checking with isBufferAvailable
27BBuffer *
28BufferMixer::GetOutputBuffer() {
29	// Do the merging of all buffers in the groupedBuffers map
30	// into the primary buffer and return that buffer.
31	// The primary buffer is removed;
32
33	BBuffer *outputBuffer = groupedBuffers[0];
34	groupedBuffers[0] = NULL;
35
36	std::map<int32, BBuffer*>::iterator each;
37
38	for (each=groupedBuffers.begin(); each != groupedBuffers.end(); each++) {
39		if (each->second != outputBuffer) {
40			if (each->second != NULL) {
41				Merge(each->second, outputBuffer);
42			}
43		}
44	}
45
46	return outputBuffer;
47}
48
49#define ALPHABLEND(source, destination, alpha) (((destination) * (256 - (alpha)) + (source) * (alpha)) >> 8)
50
51void
52BufferMixer::Merge(BBuffer *input, BBuffer *output) {
53	// Currently only deals with RGBA32
54
55	uint8 *source = (uint8 *)input->Data();
56	uint8 *destination = (uint8 *)output->Data();
57	uint32 size = input->Header()->size_used / 4;
58	uint8 alpha = 0;
59	uint8 c1, c2, c3;
60
61	for (uint32 i=0; i<size; i++) {
62		c1    = *source++;
63		c2    = *source++;
64		c3    = *source++;
65		alpha = *source++;
66		destination[0] = ALPHABLEND(c1, destination[0], alpha);
67		destination[1] = ALPHABLEND(c2, destination[1], alpha);
68		destination[2] = ALPHABLEND(c3, destination[2], alpha);
69		destination[3] = 0x00;
70		destination += 4;
71	}
72}
73
74void
75BufferMixer::AddBuffer(int32 id, BBuffer *buffer, bool isPrimary) {
76	BBuffer *oldBuffer;
77
78	if (isPrimary) {
79		oldBuffer = groupedBuffers[0];
80		groupedBuffers[0] = buffer;
81	} else {
82		oldBuffer = groupedBuffers[id];
83		groupedBuffers[id] = buffer;
84	}
85
86	if (oldBuffer != NULL) {
87		oldBuffer->Recycle();
88	}
89}
90
91void
92BufferMixer::RemoveBuffer(int32 id) {
93	BBuffer *oldBuffer;
94
95	if (uint32(id) < groupedBuffers.size()) {
96		oldBuffer = groupedBuffers[id];
97		groupedBuffers[id] = NULL;
98
99		if (oldBuffer != NULL) {
100			oldBuffer->Recycle();
101		}
102	}
103}
104