summaryrefslogtreecommitdiffstats
path: root/src/livarot/BitLigne.cpp
blob: 2e44359f8c9c5f8fd86da4bc01c07bf481b1e9b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * TODO: insert short description here
 *//*
 * Authors:
 * see git history
 * Fred
 *
 * Copyright (C) 2018 Authors
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include "BitLigne.h"

#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <cstdio>
#include <glib.h>

BitLigne::BitLigne(int ist,int ien,float iScale)
{
  scale=iScale;
  invScale=1/iScale;
	st=ist;
	en=ien;
	if ( en <= st ) en=st+1;
	stBit=(int)floor(((float)st)*invScale); // round to pixel boundaries in the canvas
	enBit=(int)ceil(((float)en)*invScale);
	int  nbBit=enBit-stBit;
	if ( nbBit&31 ) {
		nbInt=nbBit/32+1;
	} else {
		nbInt=nbBit/32;
	}
  nbInt+=1;
	fullB=(uint32_t*)g_malloc(nbInt*sizeof(uint32_t));
	partB=(uint32_t*)g_malloc(nbInt*sizeof(uint32_t));

	curMin=en;
	curMax=st;
}
BitLigne::~BitLigne()
{
	g_free(fullB);
	g_free(partB);
}

void             BitLigne::Reset()
{
	curMin=en;
	curMax=st+1;
	memset(fullB,0,nbInt*sizeof(uint32_t));
	memset(partB,0,nbInt*sizeof(uint32_t));
}
int              BitLigne::AddBord(float spos,float epos,bool full)
{
	if ( spos >= epos ) return 0;
	
  // separation of full and not entirely full bits is a bit useless
  // the goal is to obtain a set of bits that are "on the edges" of the polygon, so that their coverage
  // will be 1/2 on the average. in practice it's useless for anything but the even-odd fill rule
	int   ffBit,lfBit; // first and last bit of the portion of the line that is entirely covered
	ffBit=(int)(ceil(invScale*spos));
	lfBit=(int)(floor(invScale*epos));
	int   fpBit,lpBit; // first and last bit of the portion of the line that is not entirely but partially covered
	fpBit=(int)(floor(invScale*spos));
	lpBit=(int)(ceil(invScale*epos));
  
  // update curMin and curMax to reflect the start and end pixel that need to be updated on the canvas
	if ( floor(spos) < curMin ) curMin=(int)floor(spos);
	if ( ceil(epos) > curMax ) curMax=(int)ceil(epos);

  // clamp to the line
	if ( ffBit < stBit ) ffBit=stBit;
	if ( ffBit > enBit ) ffBit=enBit;
	if ( lfBit < stBit ) lfBit=stBit;
	if ( lfBit > enBit ) lfBit=enBit;
	if ( fpBit < stBit ) fpBit=stBit;
	if ( fpBit > enBit ) fpBit=enBit;
	if ( lpBit < stBit ) lpBit=stBit;
	if ( lpBit > enBit ) lpBit=enBit;
  
  // offset to get actual bit position in the array
	ffBit-=stBit;
	lfBit-=stBit;
	fpBit-=stBit;
	lpBit-=stBit;

  // get the end and start indices of the elements of fullB and partB that will receives coverage
	int   ffPos=ffBit>>5;
	int   lfPos=lfBit>>5;
	int   fpPos=fpBit>>5;
	int   lpPos=lpBit>>5;
  // get bit numbers in the last and first changed elements of the fullB and partB arrays
	int   ffRem=ffBit&31;
	int   lfRem=lfBit&31;
	int   fpRem=fpBit&31;
	int   lpRem=lpBit&31;
  // add the coverage
  // note that the "full" bits are always a subset of the "not empty" bits, ie of the partial bits
  // the function is a bit lame: since there is at most one bit that is partial but not full, or no full bit,
  // it does 2 times the optimal amount of work when the coverage is full. but i'm too lazy to change that...
	if ( fpPos == lpPos ) { // only one element of the arrays is modified
    // compute the vector of changed bits in the element
		uint32_t  add=0xFFFFFFFF;
		if ( lpRem < 32 ) {add>>=32-lpRem;add<<=32-lpRem; }
    if ( lpRem <= 0 ) add=0;
		if ( fpRem > 0) {add<<=fpRem;add>>=fpRem;}
    // and put it in the line
    fullB[fpPos]&=~(add); // partial is exclusive from full, so partial bits are removed from fullB
    partB[fpPos]|=add;    // and added to partB
    if ( full ) { // if the coverage is full, add the vector of full bits
      if ( ffBit <= lfBit ) {
        add=0xFFFFFFFF;
        if ( lfRem < 32 ) {add>>=32-lfRem;add<<=32-lfRem;}
        if ( lfRem <= 0 ) add=0;
        if ( ffRem > 0 ) {add<<=ffRem;add>>=ffRem;}
        fullB[ffPos]|=add;
        partB[ffPos]&=~(add);
      }
    }
	} else {
    // first and last elements are differents, so add what appropriate to each
		uint32_t  add=0xFFFFFFFF;
		if ( fpRem > 0 ) {add<<=fpRem;add>>=fpRem;}
    fullB[fpPos]&=~(add);
    partB[fpPos]|=add;

		add=0xFFFFFFFF;
		if ( lpRem < 32 ) {add>>=32-lpRem;add<<=32-lpRem;}
    if ( lpRem <= 0 ) add=0;
    fullB[lpPos]&=~(add);
    partB[lpPos]|=add;

    // and fill what's in between with partial bits
    if ( lpPos > fpPos+1 ) memset(fullB+(fpPos+1),0x00,(lpPos-fpPos-1)*sizeof(uint32_t));
    if ( lpPos > fpPos+1 ) memset(partB+(fpPos+1),0xFF,(lpPos-fpPos-1)*sizeof(uint32_t));

		if ( full ) { // is the coverage is full, do your magic
      if ( ffBit <= lfBit ) {
        if ( ffPos == lfPos ) {
          add=0xFFFFFFFF;
          if ( lfRem < 32 ) {add>>=32-lfRem;add<<=32-lfRem;}
          if ( lfRem <= 0 ) add=0;
          if ( ffRem > 0 ) {add<<=ffRem;add>>=ffRem;}
          fullB[ffPos]|=add;
          partB[ffPos]&=~(add);
        } else {
          add=0xFFFFFFFF;
          if ( ffRem > 0 ) {add<<=ffRem;add>>=ffRem;}
          fullB[ffPos]|=add;
          partB[ffPos]&=~add;
          
          add=0xFFFFFFFF;
          if ( lfRem < 32 ) {add>>=32-lfRem;add<<=32-lfRem;}
          if ( lfRem <= 0 ) add=0;
          fullB[lfPos]|=add;
          partB[lfPos]&=~add;
          
          if ( lfPos > ffPos+1 ) memset(fullB+(ffPos+1),0xFF,(lfPos-ffPos-1)*sizeof(uint32_t));
          if ( lfPos > ffPos+1 ) memset(partB+(ffPos+1),0x00,(lfPos-ffPos-1)*sizeof(uint32_t));
        }
      }
    }
	}
	return 0;
}


void             BitLigne::Affiche()
{
	for (int i=0;i<nbInt;i++) printf(" %.8x",fullB[i]);
	printf("\n");
	for (int i=0;i<nbInt;i++) printf(" %.8x",partB[i]);
	printf("\n\n");
}